让我们说我想抓一个网页,并提取一些数据。我最有可能写这样的东西:
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!
语句?
答案 0 :(得分:9)
关键是我们不产生任何新线程。在整个工作流程中,ThreadPool消耗了1或0个活动线程。 (例外,直到第一个'!',代码在执行Async.Run的用户线程上运行。)“let!”当Async操作在海上时,让我们离开一个线程,然后在操作返回时从ThreadPool中获取一个线程。 (性能)优势是对ThreadPool的压力较小(当然主要的用户优势是简单的编程模型 - 比您编写的所有BeginFoo / EndFoo /回调内容要好一百万倍。)
答案 1 :(得分:3)
我正在写一个答案,但Brian打败了我。我完全同意他的观点。
我想补充一点,如果你想并行化同步代码,那么正确的工具就是PLINQ,而不是异步工作流,如Don Syme explains。