2009-01-30 63 views
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 

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

尽管上面的工作流生成了多个线程,但执行顺序是串行的,因为工作流中的每个项目都依赖于前一个项目。在其他线程返回之前,无法评估工作流程中的任何项目。

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

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

回答

9

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

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

+0

好吧,让!不产生多个线程,它只是释放线程句柄回线程池:)我想这带有少量的开销,所以我可能不会“让!”每一行。是否有任何规定放置“让!”在最佳位置? – Juliet 2009-01-30 17:59:41

3

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

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