我試圖理解GetAwaiter().GetResult()
. 我知道如果可能的話不應該使用它,但在這種情況下我不能使用 async/await,所以我必須從同步問題中的異步函式中獲取結果。
讓我們考慮這個簡單的 Blazor 服務器應用程式:
@page "/"
<button @onclick="GetAwaiterGetResultOnTask">Task GetAwaiter().GetResult()</button>
<button @onclick="GetAwaiterGetResultOnFunction">Function GetAwaiter().GetResult()</button>
<p>@_message</p>
@code {
private string _message;
private async Task<string> AsyncFunction(string message)
{
await Task.Delay(500);
return message;
}
private void GetAwaiterGetResultOnTask()
{
_message = Task.Run(() => AsyncFunction("Message from GetAwaiterGetResultOnTask")).GetAwaiter().GetResult();
}
private void GetAwaiterGetResultOnFunction()
{
_message = AsyncFunction("Message from GetAwaiterGetResultOnFunction").GetAwaiter().GetResult();
}
}
呼叫該函式GetAwaiterGetResultOnFunction
會導致死鎖。但是,當我呼叫GetAwaiterGetResultOnTask
它時卻沒有。
這些函式之間的主要區別是什么?為什么在呼叫時不會導致死鎖Task.Run
?
uj5u.com熱心網友回復:
await
知道一種叫做SynchronizationContext
. 如果存在這樣的背景關系(SynchronizationContext.Current
不為空),則將后續的延續await
傳遞給該背景關系,因為它應該知道如何更好地處理它(除非您明確告訴不要這樣做,使用await someTask.ConfigureAwait(continueOnCapturedContext: false)
)
大多數 UI 框架不喜歡從多個執行緒并發訪問 UI,因為這通常會導致各種難以除錯的問題。它們SynchronizationContext
用于強制執行單一的執行流程。為此 - 他們通常將發布到 SynchronizationContext 的回呼放在某種佇列中,并在單個“UI”執行緒上逐個執行它們。
Blazor 也這樣做。GetAwaiterGetResultOnFunction
你的情況是在那個“UI”執行緒上執行的,SynchronizationContext
可用。當執行到達await Task.Delay
內部時AsyncFunction
- 當前背景關系被捕獲,并注意到當Task.Delay
完成時 - 函式的其余部分應發布到背景關系中以供執行。
然后通過執行GetResult
從AsyncFunction
. 然后Task.Delay
完成,其余的函式被發布到SynchronizationContext
Blazor 執行。但是,要做到這一點,Blazor 需要您剛剛阻止的相同 UI 執行緒,從而導致死鎖。
當您呼叫時GetAwaiterGetResultOnTask
-AsyncFunction
不在 Blazor 的“UI”執行緒上運行 - 它在其他(執行緒池)執行緒上運行。SynchronizationContext
為空,之后的部分await Task.Delay
將在某個執行緒池執行緒上運行,并且不需要“UI”執行緒來完成。然后就沒有死鎖了。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/318808.html
下一篇:Java不等待異步呼叫回應