C# ConfigureWait
ConfigureAwait
参数为bool类型。true:尝试将延续任务封送回原始上下文
我们一般使用的是false,用于避免强制在原始上下文或调度程序中进行回调。
原理:
以await DoSomeThingAsync().ConfigureAwait(false)为例。
await等待返回后,需要获取上下文(比如UI)的线程,然后继续执行后续的代码。
本来是回到UI线程去执行的,这里添加了ConfigureAwait(false)后,就从线程池中使用工作线程去执行后续代码了。
1 private async void ButtonBase_OnClick(object sender, RoutedEventArgs e) 2 { 3 Debug.WriteLine($"ButtonBase_OnClick-start"); 4 await DoA(); 5 Debug.WriteLine($"ButtonBase_OnClick-end"); 6 } 7 private async Task DoA() 8 { 9 Debug.WriteLine($"DoA-start"); 10 await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false); 11 Debug.WriteLine($"DoA-end"); 12 }
如上代码,输出调试信息位置的几处,所处线程分别是:
ButtonBase_OnClick-start -- UI线程
DoA-start -- UI线程
DoA-end -- 工作线程
ButtonBase_OnClick-end -- UI线程
可以看出,DoA方法中调用ConfigureAwait(false)后后续代码可以在新的工作线程中执行,ButtonBase_OnClick不调用则会默认切换至UI线程继续执行后续代码。
使用-提升性能
减少了回调原始线程(比如UI线程),可以适当减少因排队回调次数过多造成的性能影响
不必要回到原始线程,可以减少原始线程的处理。这也是多线程编程的一个实现方式。
使用-避免死锁
什么情况会死锁?
当你基于某些原因(比如想将异步方法转同步、或者仅仅只是想等待完成),使用了.Wait()、.Result、GetAwaiter().GetResult()方法时,可能会出现死锁。
1 private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 2 { 3 Debug.WriteLine($"ButtonBase_OnClick-start"); 4 DoA().Wait(); 5 Debug.WriteLine($"ButtonBase_OnClick-end"); 6 } 7 private async Task DoA() 8 { 9 Debug.WriteLine($"DoA-start"); 10 await Task.Delay(TimeSpan.FromSeconds(5)); 11 Debug.WriteLine($"DoA-end"); 12 }
如上,当使用了.Wait()后,在DoA方法中有任务等待,就会出现死锁。
为什么会死锁?
以上方法,是通过同步阻塞的方式来完成等待的。我们的UI上下文只有一个线程(并发数量是1),在调用以上方法后,子方法中await无法回调至UI线程(因为唯一的线程已经被阻塞了)。
怎么解决死锁?
在await DoSomeThingAsync()后添加.ConfigureAwait(false)
,那么它就不会将回调排队送回原始上下文,进而避免了死锁。
其实就是假装没有上下文,然后默认让线程池线程处理。
一些问题
1.使用.ConfigureAwait(false)后,后续代码中有调用UI线程如控件,会有线程调度异常
-- 建议在UI层,不使用.
ConfigureAwait(false)。或者只对需要调用UI线程的代码,添加切换至UI线程的逻辑(如Dispatcher.InvokeAsync)
2.添加.ConfigureAwait(false)后,后续的代码并没有预期的在工作线程执行。
-- 这是可能的。因为await需要等待时,才会需要切换至原始上下文。当等待已经完成的Task时,后续代码将会保持同步运行,无需上下文的回调
以上是个人总结后,相对简单、重要的部分。
你也可以看看其它:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)