2009-01-30 118 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