簡體   English   中英

從 F# 調用 C# 異步方法會導致死鎖

[英]Calling C# async method from F# results in a deadlock

我有一組 F# 腳本,它們調用我們創建的各種庫,其中許多公開了最初用 C# 編寫的異步方法。 最近我發現腳本停止工作了(我想距離我上次使用它們大約有半年時間了,然后它們工作了)。

我試圖隔離問題並想出了以下重現它的代碼:

首先,讓我們考慮一個包含以下 C# 類的庫:

    public class AsyncClass
    {
        public async Task<string> GetStringAsync()
        {
            var uri = new Uri("https://www.google.com");
            var client = new HttpClient();
            var response = await client.GetAsync(uri);
            var body = await response.Content.ReadAsStringAsync();
            return body;
        }
    }

接下來,讓我們使用以下代碼從 F#(FSX 腳本)調用庫:

let asyncClient = AsyncClass()

let strval1 = asyncClient.GetStringAsync() |> Async.AwaitTask |> Async.RunSynchronously
printfn "%s" strval1

let strval2 = 
    async {
        return! asyncClient.GetStringAsync() |> Async.AwaitTask
    } |> Async.RunSynchronously
printfn "%s" strval2

獲取strval1以死鎖strval2 ,而strval2被檢索得很好(我很確定幾個月前第一個場景也曾經工作過,所以看起來某種更新可能導致了這種情況)。

這很可能是一個同步上下文問題,其中線程基本上是“等待自己完成”,但我不明白第一次調用到底有什么問題 - 我看不出有什么問題。

StackOverflow 上的類似問題:

因此 .net Task將立即啟動,而 F# async {}是惰性的。 因此,當您將任務包裝在async { }它會變得懶惰,因此將具有Async.RunSynchronously所期望的特征。

通常,我只在執行 f# 異步操作時使用 async {},如果我使用 .net 任務,我將使用TaskBuilder.fs (在 nuget 中可用)。 它更了解像ConfigureAwait(continueOnCapturedContext: false)這樣的Task特性。

open FSharp.Control.Tasks.V2.ContextInsensitive

task {
    let! x = asyncClient.GetStringAsync()
    //do something with x
}

暫無
暫無

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

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