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