使用异步工作流并行化的最佳实践

时间:2009-01-30 17:45:40

标签: f# asynchronous async-workflow

让我们说我想抓一个网页,并提取一些数据。我最有可能写这样的东西:

let getAllHyperlinks(url:string) =
    async {  let req = WebRequest.Create(url)
             let! rsp = req.GetResponseAsync()
             use stream = rsp.GetResponseStream()             // depends on rsp
             use reader = new System.IO.StreamReader(stream)  // depends on stream
             let! data = reader.AsyncReadToEnd()              // depends on reader
             return extractAllUrls(data) }                    // depends on data

let!告诉F#在另一个线程中执行代码,然后将结果绑定到变量,然后继续处理。上面的示例使用两个let语句:一个用于获取响应,另一个用于读取所有数据,因此它至少生成两个线程(如果我错了,请纠正我)。

虽然上面的工作流程会生成多个线程,但执行顺序是串行的,因为工作流程中的每个项目都取决于前一个项目。在其他线程返回之前,无法在工作流程中进一步评估任何项目。

在上面的代码中有多个let!有什么好处吗?

如果没有,此代码如何更改以利用多个let!语句?

2 个答案:

答案 0 :(得分:9)

关键是我们产生任何新线程。在整个工作流程中,ThreadPool消耗了1或0个活动线程。 (例外,直到第一个'!',代码在执行Async.Run的用户线程上运行。)“let!”当Async操作在海上时,让我们离开一个线程,然后在操作返回时从ThreadPool中获取一个线程。 (性能)优势是对ThreadPool的压力较小(当然主要的用户优势是简单的编程模型 - 比您编写的所有BeginFoo / EndFoo /回调内容要好一百万倍。)

另见http://cs.hubfs.net/forums/thread/8262.aspx

答案 1 :(得分:3)

我正在写一个答案,但Brian打败了我。我完全同意他的观点。

我想补充一点,如果你想并行化同步代码,那么正确的工具就是PLINQ,而不是异步工作流,如Don Syme explains