簡體   English   中英

幫我理解F#線程

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM