假设我想抓取一个网页,并提取一些数据。我很可能会写这样的东西:
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# 在另一个线程中执行代码,然后将结果绑定(bind)到变量,然后继续处理。上面的示例使用了两个 let 语句:一个用于获取响应,一个用于读取所有数据,因此它至少会产生两个线程(如果我错了,请纠正我)。尽管上面的工作流产生了几个线程,但执行顺序是连续的,因为工作流中的每个项目都依赖于前一个项目。在其他线程返回之前,实际上不可能进一步评估工作流程中的任何项目。
拥有多个
let!
有什么好处吗?在上面的代码中? 如果不是,如何更改此代码以利用多个
let!
陈述?
最佳答案
关键是我们没有产生任何新线程。在整个工作流过程中,有 1 个或 0 个事件线程从 ThreadPool 中被消耗。 (一个异常(exception),直到第一个'!',代码在执行 Async.Run 的用户线程上运行。)“让!”在 Async 操作在海上时释放一个线程,然后在操作返回时从 ThreadPool 中拾取一个线程。 (性能)优势是对 ThreadPool 的压力较小(当然,主要的用户优势是简单的编程模型 - 比您编写的所有 BeginFoo/EndFoo/callback 内容好一百万倍)。
另见 http://cs.hubfs.net/forums/thread/8262.aspx
关于f# - 使用异步工作流进行并行化的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/496468/