ConfigureAwait(true) 和 ConfigureAwait(false 首先,让我们回顾一下原版 ConfigureAwait 的语义和历史,它采用了一个名为 continueOnCapturedContext 既然谈到了 ConfigureAwait(false),我想指出几个常见的误解: 1、ConfigureAwait(false) 并不是避免死锁的好方法。 ConfigureAwait(true) 和 ConfigureAwait(false) 仍具有相同的行为。但是,有一种新的 ConfigureAwait 即将出现! ConfigureAwait(ConfigureAwaitOptions) ConfigureAwait 有几个新选项。 以前,当 ConfigureAwait 只接受一个布尔参数时,你可以说”ConfigureAwait 配置了 await“;但现在你必须说得更具体:”ConfigureAwait 返回了一个已配置的 await
ConfigureAwait(false)能做什么呢? 默认情况下,当您使用async/await时,它将在开始请求的原始线程上继续运行(状态机)。 如果一不小心,便会引发大批量的死锁 如果有同步方法调用异步方法,则必须使用ConfigureAwait(false)。如果不这样做,就会立即掉进死锁陷阱。 (false).GetAwaiter().GetResult(); .NET Standard与ConfigureAwait(false) 在.NETCore中,微软删除了导致我们在任何地方都需要ConfigureAwait 因此,ASP.NETCore应用程序在技术上不需要任何ConfigureAwait(false)逻辑,因为它是多余的。 ConfigureAwait(false) 贯穿始终 如果同步调用有可能调用您的异步方法,那么在整个调用堆栈的每个异步调用上,您都将被迫设置. configureAwait (false) !
ConfigureAwait方法的作用和原理 ConfigureAwait方法是Task类中的一个实例方法,它用于配置任务的运行上下文。 ConfigureAwait方法的原理是通过设置Task对象的一个内部状态来实现的。 ConfigureAwait方法的使用场景 非UI线程场景 在非UI线程中执行任务时,可以使用ConfigureAwait(false)来告知任务在执行期间不需要同步回原始上下文。 因此,在UI线程使用ConfigureAwait(false)时需要特别小心。 (false).ConfigureAwait(true); // 继续在非UI线程中执行其他逻辑 } 总结 ConfigureAwait方法在异步编程中扮演着重要的角色,通过配置任务的运行上下文
ConfigureAwait方法的作用和原理 ConfigureAwait方法是Task类中的一个实例方法,它用于配置任务的运行上下文。 ConfigureAwait方法的原理是通过设置Task对象的一个内部状态来实现的。 ConfigureAwait方法的使用场景 非UI线程场景 在非UI线程中执行任务时,可以使用ConfigureAwait(false)来告知任务在执行期间不需要同步回原始上下文。 因此,在UI线程使用ConfigureAwait(false)时需要特别小心。 (false).ConfigureAwait(true); // 继续在非UI线程中执行其他逻辑 } 总结 ConfigureAwait方法在异步编程中扮演着重要的角色,通过配置任务的运行上下文
类库使用ConfigureAwait.Fody配置全局ConfigureAwait (false)取消异步上下文切换 - 唐 森 - 博客园 https://www.cnblogs.com/townsend ,也就能提高性能 } 如果每一个异步方法调用都加上ConfigureAwait(false)则改动比较大,这时候就可以利用ConfigureAwait.Fody来做全局配置, 编译后的就会在项目里的每一个异步调用后面加上 ConfigureAwait(false),相当于AOP静态织入。 文件 默认是没有设置ConfigureAwait(false),需要在FodyWeavers.xml的ConfigureAwait节点添加 ContinueOnCapturedContext="false .ConfigureAwait(continueOnCapturedContext: false) ConfigureAwait相关参考资料: https://www.cnblogs.com/xiaoxiaotank
在编写异步方法时,使用 ConfigureAwait(false) 避免使用者死锁 发布于 2018-03-23 13:54 对第 3 种情况,由于指定了 ConfigureAwait(false),这意味着通知异步状态机 AsyncMethodStateMachine 并不需要使用设置好的 SynchronizationContext 这样,当你在代码中写出 await 时,分析器会提示你 CA2007 警告,你必须显式设置 ConfigureAwait(false) 或 ConfigureAwait(true) 来提醒你是否需要使用默认的
请考虑调用 Task.ConfigureAwait(Boolean) 以表示延续任务意图。 如何解决冲突 若要解决冲突,请在等待的 Task 上调用 ConfigureAwait。 对任务调用 ConfigureAwait(true) 与未显式调用 ConfigureAwait 的行为相同。 通过显式调用此方法,可让读取者知道你是有意要对原始同步上下文执行延续任务。 对任务调用 ConfigureAwait(false) 可将延续任务安排到线程池,从而避免 UI 线程上出现死锁。 对于与应用无关的库,传递 false 是一个好的选择。 : public async Task Execute() { Task task = null; await task.ConfigureAwait(false); } 何时禁止显示警告 常见问题解答 是否应使用 ConfigureAwait (false) 来等待任务?
await _httpClient.GetFromJsonAsync<ApiResponse<List<StudentViewModel>>>("api/Student/GetAllStudent").ConfigureAwait await _httpClient.PutAsJsonAsync($"api/Student/UpdateStudent/{studentInfo.StudentID}", studentInfo).ConfigureAwait var addResult = await _httpClient.PostAsJsonAsync("api/Student/CreateStudent", studentInfo).ConfigureAwait ; try { var students = await _studentHelper.QueryAllAsync().ConfigureAwait (false); var studentsListDto = await GetStudentClassInfo(students).ConfigureAwait(false
await _httpClient.GetFromJsonAsync<ApiResponse<List<StudentViewModel>>>("api/Student/GetAllStudent").ConfigureAwait await _httpClient.PutAsJsonAsync($"api/Student/UpdateStudent/{studentInfo.StudentID}", studentInfo).ConfigureAwait var addResult = await _httpClient.PostAsJsonAsync("api/Student/CreateStudent", studentInfo).ConfigureAwait ; try { var students = await _studentHelper.QueryAllAsync().ConfigureAwait (false); var studentsListDto = await GetStudentClassInfo(students).ConfigureAwait(false
(false); int fullMsgLength2 = await ReadInt32().ConfigureAwait(false); Debug.Assert(fullMsgLength (false); Debug.Assert(encrypted == Encrypted); short reserved = await ReadByte().ConfigureAwait (false); byte zero = await ReadByte().ConfigureAwait(false); Debug.Assert(zero == ByteZero); (false); await stream.WriteAsync(new byte[] { Encrypted}, cancellationToken).ConfigureAwait(false) stream.WriteAsync(body, cancellationToken).ConfigureAwait(false); await stream.WriteAsync(new byte
误用ConfigureAwait(false) 问题: 虽然ConfigureAwait(false)在库或后台代码中用于提高性能很有用,但在UI应用程序中使用它可能导致同步问题。 Data loaded with ConfigureAwait(false) in UI context Elapsed time with ConfigureAwait(false) in UI context Data loaded with ConfigureAwait(false) in non-UI context Elapsed time with ConfigureAwait(false) in non-UI 在非UI上下文中使用ConfigureAwait(false)时:方法LoadDataWithConfigureAwaitFalseInNonUIContext在非UI上下文中正确地使用了ConfigureAwait 在非UI上下文中正确地使用ConfigureAwait(false)可以通过避免不必要的上下文切换来提高性能。
(false); // 必须写 ConfigureAwait(false) // 此处的代码将不会返回原线程执行;不过这里一般不写代码。} string data = _getStringDataTask.Result; // after work} 这种实现方式需要注意死锁问题,如果不使用 ConfigureAwait(false) 立刻死锁(deadlock) - walterlv 在编写异步方法时,使用 ConfigureAwait(false) 避免使用者死锁 - walterlv 一个神奇的异步转同步的方式 有如下一个 GetDataAsync (false); // 必须写 ConfigureAwait(false) // 使用下面这段代码会死锁 // return await GetAvaiableAsync ().ConfigureAwait(false); } } 这样,外部就可以调用 GetData 这个很普通的方法,而不用调用 GetDataAsync 这个方法了。
⚠️ 陷阱2——上下文重捕获与缺失的ConfigureAwait(false) public async Task DoWorkAsync() { await SomeIoAsync(); // ❌ 可能重捕获ASP.NET请求上下文 DoSomething(); } ✅ 修复方案2——在非UI代码中全面应用ConfigureAwait(false) public async Task DoWorkAsync() { await SomeIoAsync().ConfigureAwait(false); // ✅ 保持在线程池 DoSomething(); } 经验法则 : UI层 → 不用ConfigureAwait(false) 其他场景 → 必须使用 ⚠️ 陷阱3——Task.Run的洪水攻击 public async Task ProcessAsync() { ConfigureAwait(false):库和服务器代码必须使用 3.
async Task ExecuteAsync(CancellationToken stoppingToken) { await BootstrapAsync(stoppingToken).ConfigureAwait context.IsStopping) try { await _inner.ProcessAsync(context).ConfigureAwait ", _inner.ToString()); await context.WaitAsync(TimeSpan.FromSeconds(2)).ConfigureAwait , CultureInfo.InvariantCulture)).ConfigureAwait(false); } else { await _dispatcher.EnqueueToPublish(message).ConfigureAwait(false);
await _httpClient.PutAsJsonAsync($"api/SchoolClass/UpdateClass/{studentInfo.ClassID}", studentInfo).ConfigureAwait var delResult = await _httpClient.DeleteAsync($"api/SchoolClass/DeleteClass/{item.ClassID}").ConfigureAwait querySchoolClass = await _schoolClassHelper.QuerySingleAsync(c => c.ClassName == schoolClass.ClassName).ConfigureAwait try { var classes = await _schoolClassHelper.QueryAllAsync().ConfigureAwait var schoolClass = await _schoolClassHelper.QuerySingleAsync(c => c.ClassID == classId).ConfigureAwait
try { var classes = await _schoolClassHelper.QueryAllAsync().ConfigureAwait var schoolClass = await _schoolClassHelper.QuerySingleAsync(c => c.ClassID == classId).ConfigureAwait ; try { var students = await _studentHelper.QueryAllAsync().ConfigureAwait var student = await _studentHelper.QuerySingleAsync(x => x.StudentID == studentID).ConfigureAwait var student = await _studentHelper.QuerySingleAsync(x => x.StudentID == studentID).ConfigureAwait
常见错误六:忽略 ConfigureAwait(false),导致上下文捕获引发死锁 ❌ 错误示例: // 默认捕获当前上下文,可能导致线程阻塞 public async Task DoWorkAsync ✅ 正确做法: 在非 UI 代码中,建议加上 .ConfigureAwait(false) 来避免上下文捕获: // 避免上下文捕获,提高性能并防止死锁 public async Task DoWorkAsync () { await SomeIoOperationAsync().ConfigureAwait(false); } 小贴士: ★在类库、通用方法、后台服务中,建议始终加上 .ConfigureAwait 仅限事件处理,其他一律用 Task ❌ 不需要异步却加了 async ✅ 用 Task.FromResult() 替代 ❌ 每次都 new HttpClient ✅ 全局复用或通过 DI 获取 ❌ 忽略 ConfigureAwait (false) ✅ 非 UI 代码中加上 .ConfigureAwait(false) 写在最后 async/await 是 .NET 中非常强大的工具,但也是一把双刃剑。
practices (both covered in my intro post) that avoid this situation: In your “library” async methods, use ConfigureAwait { using (var client = new HttpClient()) { var jsonString = await client.GetStringAsync(uri).ConfigureAwait Using ConfigureAwait(false) to avoid deadlocks is a dangerous practice. You would have to use ConfigureAwait(false) for every await in the transitive closure of all methods Using ConfigureAwait(false) to avoid deadlock is at best just a hack).
{ var response = await _httpClient.SendAsync(httpRequestMessage, cancellationToken).ConfigureAwait ::Microsoft.Extensions.Http.AutoClient.AutoClientHttpError.CreateAsync(response, cancellationToken).ConfigureAwait response.Content, _autoClientOptions.JsonSerializerOptions, cancellationToken) .ConfigureAwait ::Microsoft.Extensions.Http.AutoClient.AutoClientHttpError.CreateAsync(response, cancellationToken).ConfigureAwait ::Microsoft.Extensions.Http.AutoClient.AutoClientHttpError.CreateAsync(response, cancellationToken).ConfigureAwait
new AddressBindContext(_serverAddresses, Options, Trace, OnBind); await BindAsync(cancellationToken).ConfigureAwait , cancellationToken).ConfigureAwait(false); 在 AddressBinder 的 BindAsync 方法中创建了多种策略进行绑定 var strategy = await strategy.BindAsync(context, cancellationToken).ConfigureAwait(false); 例如 AddressesStrategy,它有自己的一个绑定方法 cancellationToken) { try { await context.CreateBinding(endpoint, cancellationToken).ConfigureAwait , cancellationToken).ConfigureAwait(false); 002.jpg 所以整个过程的重点在第一步的 OnBind,而 OnBind 的重点在于 TransportManager