[英]help me reason about F# threads
在使用一些F#(通過MonoDevelop)時,我編寫了一個例程,用一個線程列出目錄中的文件:
let rec loop (path:string) =
Array.append
(
path |> Directory.GetFiles
)
(
path
|> Directory.GetDirectories
|> Array.map loop
|> Array.concat
)
然后是它的異步版本:
let rec loopPar (path:string) =
Array.append
(
path |> Directory.GetFiles
)
(
let paths = path |> Directory.GetDirectories
if paths <> [||] then
[| for p in paths -> async { return (loopPar p) } |]
|> Async.Parallel
|> Async.RunSynchronously
|> Array.concat
else
[||]
)
在小目錄上,異步版本工作正常。 在更大的目錄(例如,數千個目錄和文件)上,異步版本似乎掛起了。 我錯過了什么?
我知道創建數千個線程永遠不會是最有效的解決方案 - 我只有8個CPU - 但我感到困惑的是,對於較大的目錄,異步函數只是沒有響應(即使在半小時后)。 然而,它並沒有明顯地失敗,這令我感到困惑。 是否有一個耗盡的線程池?
這些線程如何實際工作?
編輯:
根據這份文件 :
Mono> = 2.8.x有一個新的線程池,它更難以死鎖。 如果你得到一個線程池死鎖的可能性是你的程序試圖陷入僵局。
:d
是的,很可能你是壓倒Mono線程池,這會使你的系統性能停滯不前。
如果你還記得一件事,那就是線程很貴 。 每個線程都需要自己的堆棧(大小為兆字節)和CPU時間片(需要上下文切換)。 因此,為短期任務啟動自己的線程並不是一個好主意。 這就是.NET有一個ThreadPool的原因。
ThreadPool是用於短任務的現有線程集合,它是異步工作流的F#用戶。 每當您運行F#異步操作時,它只是將操作委托給線程池。
問題是,當您在F#中同時生成數千個異步操作時會發生什么? 一個簡單的實現只會根據需要生成盡可能多的線程。 但是,如果您需要1,000個線程,則意味着您需要1,000 x 4MB的堆棧空間。 即使你有足夠的內存用於所有堆棧,你的CPU也會不斷地在不同的線程之間切換。 (並在內存中分頁本地堆棧。)
在IIRC中,Windows .NET實現足夠智能,不會產生大量線程,只需將工作排隊,直到有一些備用線程來執行操作。 換句話說,它會繼續添加線程,直到它有一個固定的數字,並只使用它們。 但是,我不知道Mono的線程池是如何實現的。
tl; dr:這是按預期工作的。
克里斯可能是對的。 另一個需要考慮的角度是文件系統不是固定的東西 - 當你試圖處理列表時,那些有數千個文件變化的目錄是什么? 如果是這樣,那可能會在某處造成競爭。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.