簡體   English   中英

為什么我的第二段F#異步代碼工作,但第一部分沒有?

[英]Why does my second snippet of F# async code work, but the first does not?

注意:我不是一個專業的軟件開發人員,但是我寫了很多不使用異步的代碼,所以如果這個問題真的很直接,我很抱歉。

我正在與用C#編寫的庫連接。 有一個特殊的函數(讓我們稱之為'func')返回'Threading.Tasks.Task>'

我正在使用func在F#中構建一個庫。 我在控制台應用程序中測試了以下代碼,它工作正常。

let result = 
        func()
        |> Async.AwaitTask
        |> Async.RunSynchronously
        |> Array.ofSeq

但是,當我從WinForms應用程序運行它(這最終是我想要做的)時,表單代碼中的執行塊永遠不會返回。

所以我搞亂了代碼,並嘗試了以下,這是有效的。

let result = 
        async{
            let! temp = 
                func()
                |> Async.AwaitTask

            return temp
        } |> Async.RunSynchronously |> Array.ofSeq

為什么第一個片段不起作用? 為什么第二個片段有效? 這個頁面上有什么內容可以回答這些問題嗎? 如果是這樣,那似乎並不明顯。 如果沒有,你能指點我到哪兒嗎?

第一個和第二個片段之間的區別在於AwaitTask調用發生在不同的線程上

試試這個驗證:

let printThread() = printfn "%d" System.Threading.Thread.CurrentThread.ManagedThreadId

let result = 
    printThread()
    func()
    |> Async.AwaitTask
    |> Async.RunSynchronously
    |> Array.ofSeq

let res2 = 
    printThread()
    async {
        printThread()
        let! temp = func() |> Async.AwaitTask
        return temp
    } |> Async.RunSynchronously |> Array.ofSeq

運行res2 ,您將獲得兩行輸出,其中包含兩個不同的數字。 async運行內部的線程與res2本身運行的線程不同。 潛入async會使您處於不同的線程。

現在,這與.NET TPL任務的實際工作方式相互作用。 當你去等待任務時,你不只是在一些隨機線程上得到一個回調,哦不! 相反,您的回調將通過“當前” SynchronizationContext進行調度。 這是一種特殊的野獸,其中總有一個“當前”的野獸(可以通過靜態屬性訪問 - 談論全球狀態!),你可以要求它安排“在同一個環境中”的東西,其中的概念是“相同的上下文”由實現定義。

當然,WinForms有自己的實現,恰當地命名為WindowsFormsSynchronizationContext 當你在WinForms事件處理程序中運行,並且要求當前上下文安排某些事情時,它將使用WinForms自己的事件循環 - 一個Control.Invoke進行調度。

但是,當然,由於您使用Async.RunSynchronously阻塞事件循環的線程,因此任務等待永遠不會發生。 你正在等待它發生,它正在等你釋放線程。 阿卡“僵局”。

要解決此問題,您需要在另一個線程上啟動等待,以便不使用WinForms的同步上下文 - 您不小心偶然發現的解決方案。

另一種推薦的解決方案是通過Task.ConfigureAwait明確告訴TPL不要使用“當前”上下文:

let result = 
    func().ConfigureAwait( continueOnCapturedContext = false )
    |> Async.AwaitTask
    |> Async.RunSynchronously
    |> Array.ofSeq

不幸的是,這將無法編譯,因為Async.AwaitTask需要一個Task ,而ConfigureAwait返回一個ConfiguredTaskAwaitable

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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