await前后的線程
我們都知道 await 會讓當前線程釋放回線程池,然后 await后再申請,在默認情況下一放 一申請 這兩未必是同一個線程了。
但是我們在寫WPF/winform時,如果如下
private async void Button_Click(object sender, RoutedEventArgs e)
{
// UI 線程
myButton.Content = "開始";
await Task.Delay(1000); // 這里會掛起,線程可能切換
// 恢復(fù)回來時依然是 UI 線程(默認行為)
myButton.Content = "完成";
}
會發(fā)現(xiàn),后面的UI操作 myButton.Content = 依然可以正常 ,他依然前后是在同一個UI線程中。
這里不得不記錄一下了
在 C# 的 async/await 機制里
- await 之前的代碼運行在哪個線程,取決于你是在哪個上下文調(diào)用的(比如 WPF 中就是 UI 線程)
- await 的時候,當前方法會“掛起”,然后把控制權(quán)返回給調(diào)用者。
- await 之后繼續(xù)執(zhí)行時,是否還在原線程,取決于 SynchronizationContext(同步上下文)。
總結(jié)
-
在 WPF 中,默認 await 之后 還是 UI 線程,可以繼續(xù)安全操作 UI。
-
如果用了 ConfigureAwait(false),就會放棄回 UI 線程,那時候操作 UI 就會報錯。
?? 所以一般 UI 層的代碼不要用 ConfigureAwait(false),只在底層庫里用。
WPF 的情況
在 WPF / WinForms 這樣的 UI 框架里,它們有自己的 SynchronizationContext,默認行為是:
- await 之后會自動回到原來的 UI 線程(除非你特意禁用)。
- 所以在 WPF 里,絕大多數(shù)情況下你在 UI 線程里 await 之后,繼續(xù)的代碼依然在 UI 線程,可以安全操作 UI。
所以此時正好學(xué)到另外一個知識點
什么時候會不回到 UI 線程?
await SomeTask.ConfigureAwait(false);

浙公網(wǎng)安備 33010602011771號