Async/Await 最佳实践

如何消除异步 async传染性呢? 消除异步操作传染性的解决思路就是:抛出一个未决的 Promise,并利用调用方来监听这个 Promise 的完成状态,不直接在函数中处理 asyncawait 阅读详情


其实好久以前就看过这个文章,以及类似的很多篇文章。最近在和一个新同事的交流中发现原来对async的死锁理解不是很透彻,正好最近时间比较充裕就再当一回搬运工。

本文假定你对.NET Framework 4.5 的异步编程有基本的了解,相关的建议你能够在Stack Overflow, MSDN 以及async/awai FAQ中找到。这里并不试图想讲述多少新的知识点,而是想强调几点最佳实践,以减少你阅读大量文档排查问题的时间。本文的最佳实践更多的是一些指导意见,并不是实际意义上的规则。每条意见后面都有一些例外情况,这里都已经一一列出了,具体情况下面我们分条讲解。

 

规则

描述

例外

避免使用 async void

优先使用 async Task 而不用 async void

Event handlers

Async到顶

不要混合使用 blocking 和 async 的代码

Console main method

注意配置好执行的context

尽量设置 ConfigureAwait(false)

需要context的除外

 

避免使用 async void

Task 和 Task<T> 是异步方法的通常返回值类型。在将同步代码改造成async方式过程中,我们将void 类型返回值改成async Task.

其实,这里你改写成async void 编译器不会报错。事实上,async void 存在的意义仅仅是使用在event handlers上。如果你在普通的代码中使用async void,该代码块中的异

常处理就会变得比较麻烦。

可以看到,上面的Exception 无法被直接catch. 当然你可以使用AppDomain.UnhandledException等类似方法去捕捉该异常,但是这种代码维护起来就比较麻烦。另外,Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用。Async Void 不行。同时Async void 方式比较难测试,具体原因可以参考原文。

让Async传染到顶。

这里可以称呼为async具有僵尸病毒般的传染性,async会感染周围的代码,直到顶层。其实我们只需要顺其自然,让所有代码都传染上异步特性即可。如果我们使用Task.Wait 或者Task.Result去试图阻塞async 的传播,往往便会自找苦吃。这个往往是刚接触async 异步的人最容易犯的错误,这些人往往试图将async 方法做个小小包装搞成同步的方法,以达到不修改旧代码的目的。不幸的是,这样往往会导致死锁。这个死锁的问题在MSDN,StackOverFlow已经烂大街了。

如上所示,重现这个死锁实在是太容易了。理解该死锁的原因在于理解await 处理contexts的方式。默认的,当一个未完成的Task 被await时候,当前的上下文将在该Task完成的时候重新获得并继续执行剩余的代码。这个context就是当前的SynchronizationContext除非它是空的。GUI和ASP.NET 应用程序的SynchronizationContext 有排他性,只允许一个线程运行。当await 完成的时候,它试图在它原来的代码上下文执行它剩余的部分,但是该代码上下文中已经有一个线程在了,就是那个一直在同步等待async 完成的那个线程,它们两个相互等待,因此就死锁了。

 

注意控制台程序不会导致死锁。控制台的SynchronizationContext 是类似于一个线程池的机制而不是排他的。因此当await 结束的时候,它可以重新获得原来的上下文然后执行完剩余代码返回成功。这个不同是很多人产生困惑的根源,当他们在控制台测试的时候程序跑的好好的,拷贝到GUI或者ASP.NET 程序中就发生了死锁。

因此,最佳的解决方案就是允许async 自动传染直到最上层,通常到入口点为止。控制台的Main 方法无法被标注成async,原因你懂的。因此Main 方法这里是个例外

通常全套异步需要做一些额外的工作,下面是一些必须做的额外工作。

不要使用

使用

需要获得值的时候

Task.Wait or Task.Result

await

需要等待任何一个任务

Task.WaitAny

await Task.WhenAny

需要等待所有任务完成

Task.WaitAll

await Task.WhenAll

需要等待

Thread.Sleep

await Task.Delay

     

当然如果你不打算全套使用async, 那么必须注意处理好异常信息以及防止死锁的一些方法

注意配置好执行的context

配置好continueOnCapturedContext为false可以提高性能。这个我建议直接看代码。

我们将task 配置为不需要切换为原context, 这样后面的代码将不会在GUI 线程中运行,可以减少性能的影响。除了性能有一点点提升以外,设置好context 还能够避免死锁。当然这种解决方式需要注意的点实在太多,稍不注意就又死锁了。

同步调用异步async防止死锁方案

因此网上有人给出了以下比较通用的解决方案。具体代码就不贴全了,大概思路就是对上下文的处理,以及一些异常信息的包装等,需要代码的同学自己去翻。

 

单细胞分析(19)—— 单细胞转录组基因集评分方法 在单细胞RNA测序(scRNA-seq)分析中,基因集评分(Gene Set Scoring)是一项关键任务,能帮助研究者识别细胞功能状态 阅读详情

相关推荐

YOLO26 多任务统一架构:检测 / 分割 / 姿态 / OBB 设计

YOLO26提出了一种多任务统一架构,整合了目标检测、实例分割、姿态估计和旋转框检测(OBB)四大计算机视觉任务。该架构采用共享Backbone和Neck的设计,配合轻量级任务特定Head,解决了传统方法中多模型并行带来的高开发成本、大内存占用和低推理效率问题。核心设计包括:1)共享特征提取层实现参数复用;2)模块化Head结构支持灵活任务组合;3)统一接口实现单模型多任务处理。实验表明,该架构在保持各任务性能的同时显著提升了系统效率,为多任务视觉系统提供了新的实现范式。

一键难忘的博客 637

【前端】浅谈async/await异步传染

"异步传染性"问题通常是指,当一个函数使用了asyncawait,其调用者也需要使用asyncawait处理异步操作,导致整个调用链都变成异步的。这种情况可能导致代码变得更复杂,不易维护。 类似于C# try catch的层层上抛,在某一层catch

欢迎指错||纠正||建议||水评+点赞&&评论&&关注&&转发 4039

PCBA及成品SN编码规则.pdf

PCBA及成品SN编码规则.pdf

异步函数传染

在 JavaScript 中,异步函数的传染性指的是当一个函数内部包含异步操作(例如使用了 Promise、async/await 等)时,它会将异步特性传递给调用它的函数,以及调用它们的函数,依次传递下去。这可能会导致整个调用链上的函数都需要处理异步操作。在业务场景中为了解决这个问题,可以使用以下函数,其原理是:使用报异常的方式终止代码继续运行,在异常结束之后获取上吃抛异常时得到的接口请求数据重新执行一遍函数。由于针对的是纯函数,进参相同,结果也相同,所以无需担心执行后出现副作用。

selectDele的博客 1227

【面试题】如何消除异步的传染

【代码】【面试题】如何消除异步的传染性。

shadowfall的博客 1287

关于C# async/await的一些说明

转自:https://www.jianshu.com/p/1136e79d96e6 关于C# async/await的一些说明 下文以个人对async/await的理解为基础进行一些说明。 1、自定义的几个关键概念 调用流阻塞:不同于线程阻塞,调用流阻塞只对函数过程起作用,调用流阻塞表示在一次函数调用中,执行函数代码的过程中发生的无法继续往后执行,需要在函数体中的某个语句停止的情形; 调用流阻塞点:调用流阻塞中,执行流所停下来地方的那条语句; 调用流阻塞返回:不同于线程阻塞,调用流发生阻塞的时候

狂奔之林的博客 1052

消除async传染

【代码】消除async传染性。

weixin_50845862的博客 210

C#语言中的Async/await最佳实践

如果未使用 ConfigureAwait(false) 方法标记 await 语句,它将调用相同的 UI 线程或工作线程(导致 await 语句的线程)以在 await 之后执行下一组指令。这将告诉编译器使用 threadpool 中的任何线程在 await 关键字之后执行语句,而不是特别调用 await 语句的线程。:它增加了使用 async/await 关键字的额外复杂性。4. 避免返回 await:如果中介类方法只是返回 await 方法,请不要用 async/await 标记它们。

2401_82584055的博客 1078

WPF UI异步操作:Task与async/await最佳实践

在WPF(Windows Presentation Foundation)应用程序开发中,异步操作是提升用户体验的关键技术。然而,不正确的异步实现可能导致UI卡顿、死锁或数据不一致等问题。本文将结合WPF UI框架的实际应用场景,详细介绍Task与async/await最佳实践,帮助开发者构建流畅、可靠的桌面应用。 读完本文后,您将掌握: - WPF UI线程与异步操作的关系 - async/...

gitblog_00555的博客 1452

深入浅出 C# 异步编程:掌握 async/await最佳实践

在同步编程中,执行的每个任务都会阻塞当前线程,直到任务完成。而在异步编程中,任务在等待时不会阻塞线程,其他任务可以继续执行,直到被等待的任务完成。这种非阻塞的执行方式,使得应用程序能够在处理 I/O 密集型操作时保持响应性,从而提高用户体验和系统性能。Console.WriteLine("异步任务开始");// 调用异步方法Console.WriteLine("异步任务完成");// 使用 async 关键字标记方法为异步方法Console.WriteLine("开始执行异步任务...")

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 2780

5个async/await最佳实践

微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势,学习途径等等。本文 GitHub已收录,有一线大厂面试完整考点、资料以及我的系列文章。快来免费体验ChatGpt plus版本的,我们出的钱体验地址:https://chat.waixingyun.cn/#/home可以加入网站底部技术群,一起找bug.这篇文章介绍了使用编写异步代码的 5 个最佳实践。文章中的第一个建议是在所有异步代码中使用。这样做的好处有以下几点:首先,它使代码库保持一致性。通过在所有异步代码中使用。

粉丝们务必加入微信粉丝群 435

C# 基础——async/await 的实现原理与最佳实践

C#中的async/await通过状态机机制将异步代码转换为类似同步的写法,底层依赖任务并行库实现非阻塞操作。最佳实践包括:优先返回Task而非async void;库代码使用ConfigureAwait(false)避免死锁;始终用await代替阻塞等待;正确处理异步异常;遵循命名规范。理解其原理可编写高效无死锁的异步代码,避免常见陷阱。

lwpoor123的博客 1605

C# async/await最佳实践

.NET绿叶社区出处:leavescn.com/Articles/Content/3060在C#中,async/await 是处理异步操作的重要工具,它可以改善代码的可读性和性能。以下是一些async/await最佳实践:1. 始终遵循命名规范对于异步方法,请使用以 "Async" 结尾的命名约定。这有助于识别异步方法并遵循C#的命名规范。2. 避免异步 void 方法尽量避免使用异步 voi...

weixin_68436326的博客 185

C#中async/await与Task的深度解析从原理到最佳实践

一个任务后,默认情况下,方法的后续部分会尝试在原始的同步上下文(即调用该方法时的上下文)中恢复执行。在UI应用程序(如WinForms, WPF)中,存在一个UI同步上下文,它确保所有对UI元素的更新都发生在创建它们的线程上。关键字,它们是一种编译器功能(编译器状态机),允许开发者以接近同步代码的编写方式来实现异步操作,极大地简化了异步编程的复杂度。在等待期间,原先执行该方法的线程(如UI线程)会被释放,不会被阻塞,从而可以响应其他请求或操作。类代表一个异步操作,它是对线程池工作的更高级抽象。

plxfx1209的博客 393

Chroma异步编程:Async/Await最佳实践

在当今高并发的AI应用场景中,传统的同步编程模型往往成为性能瓶颈。Chroma作为AI原生开源嵌入数据库,深度集成了Python的async/await异步编程范式,为开发者提供了高性能、高并发的数据处理能力。 **读完本文你将掌握:** - Chroma异步API的核心设计理念 - 异步客户端的最佳使用模式 - 避免常见异步编程陷阱的技巧 - 大规模并发场景下的性能优化策略 ## Chrom...

gitblog_00537的博客 998

Swift并发编程规范:async/await最佳实践指南

Swift的async/await并发模型彻底改变了我们编写异步代码的方式,让并发编程变得更加简洁和安全。根据Kodeco官方Swift代码规范,遵循正确的async/await使用规范不仅能提高代码质量,还能显著提升应用的性能和稳定性。😊 ## 异步函数声明规范 在Swift并发编程中,正确的函数声明方式至关重要。对于异步函数,应该清晰地使用`async`关键字,并在适当的时候使用`thr

gitblog_00028的博客 433

163MusicLyrics异步编程:async/await最佳实践

在音乐应用开发中,网络请求、文件操作和用户界面响应都是常见的耗时操作。传统的同步编程模式会导致界面卡顿、用户体验下降。163MusicLyrics项目通过全面采用async/await异步编程模式,实现了高效的非阻塞操作,为用户提供了流畅的音乐歌词获取体验。 本文将深入分析163MusicLyrics项目中的异步编程最佳实践,涵盖从基础的HTTP请求到复杂的批量处理场景。 ## 异步编程基础架...

gitblog_00672的博客 702

消除异步函数的传染性简单实现

消除异步函数的传染性,通过重新定义异步函数,从而消除传染

X_xiaoqi的博客 2067

消除异步任务的传染

并通过缓存的方式来处理异步请求结果,从而在后续的调用中直接使用缓存的数据。目的:防止异步操作在代码中传播,影响到其他部分的执行。

weixin_51351053的博客 882

异步编程中的最佳做法(Async/Await) --转

近日来,涌现了许多关于 Microsoft .NET Framework 4.5 中新增了对 asyncawait 支持的信息。本文旨在作为学习异步编程的“第二步”;我假设您已阅读过有关这一方面的至少一篇介绍性文章。本文不提供任何新内容,Stack Overflow、MSDN 论坛和 async/await FAQ 这类在线资源提供了同样的建议。本文只重点介绍一些淹没在文档海洋中的最佳...

weixin_30794499的博客 1560

关于c# await使用总结

在开发一个模拟人工自动网银转账的软件的时候,大量使用了async+await,在项目成功上线并且迭代了若干版本后,对于await相关的代码进行了重构,目前的结构更清晰,可扩展性更强。同时对于await的使用也从很初级,变得有一些经验,现在把这些经验总结如下: 1 awaitasync配对使用。最典型的应用如下: 下面的代码是不用线程的情况,winform就会在5秒的无响应状态后才会在t...

wingnet 1万+
上一篇: Validation failed for one or more entities. See ‘EntityValidationErrors’解决方法
codeporter
博客等级 码龄12年 0粉丝 0原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值