8

假设我想抓取一个网页,并提取一些数据。我很可能会写这样的东西:

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

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

尽管上面的工作流产生了几个线程,但执行顺序是连续的,因为工作流中的每个项目都依赖于前一个项目。在其他线程返回之前,实际上不可能进一步评估工作流程中的任何项目。

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

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

4

2 回答 2

9

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

另请参阅http://cs.hubfs.net/forums/thread/8262.aspx

于 2009-01-30T17:50:52.947 回答
3

我正在写一个答案,但布赖恩打败了我。我完全同意他的看法。

我想补充一点,如果您想并行化同步代码,正确的工具是 PLINQ,而不是异步工作流,正如Don Syme 解释的那样。

于 2009-01-30T17:54:31.660 回答