Async,Await和ConfigureAwait的关系

在.NET Framework 4.5中,async / await关键字已添加到该版本中,简化多线程操作,以使异步编程更易于使用。为了最大化利用资源而不挂起UI,你应该尽可能地尝试使用异步编程。虽然async / await让异步编程更简单,但是有一些你可能不知道的细节和注意的地方
 

640?wx_fmt=png

新关键字

微软在.NET框架中添加了async和await关键字。但是,使用它们,方法的返回类型应为Task类型。(我们将在稍后讨论例外情况)为了使用await关键字,您必须在方法定义中使用async。如果你在方法定义中放入async,你应该在主体方法的某个地方至少有一处await关键字,如果你缺少他,你通常会收到Visual Studio的一个警告。
以下是代码中的示例:

  public async Task ExecuteAsync(UpdateCarCommand request, CancellationToken token = default)	{	using (var context = _contextFactory.Create())	{	var entity = context.Cars.FirstOrDefault(a => a.Id == request.Id);	// Mapping logic	await context.SaveChangesAsync(token);	}	}

如果要从异步方法返回某些内容,可以使用Task的泛型。像以下这样(如果你想返回受影响的行数)

 public async Task<int> ExecuteAsync(UpdateCarCommand request, CancellationToken token = default)	{	using (var context = _contextFactory.Create())	{	var entity = context.Cars.FirstOrDefault(a => a.Id == request.Id);	// Mapping logic	return await context.SaveChangesAsync(token);	}	}

async.await给我们带来了什么?

虽然使用这个看起来很简单,但是它有什么帮助呢?最后,所有这些操作都是在等待数据库返回结果时(在本例中)让其他请求使用当前线程。当您向数据库、磁盘、internet等外部源发出可能需要一段时间才能运行的请求时,我们可以使用async/ wait让其他请求使用这个线程。这样,我们就不会有空闲的“worker”(线程)在那里等待完成其他任务。这就像去快餐店一样,在你点完菜之后,其他人不会点任何东西,直到你吃完为止。使用async/ await,其他人可以在你点完菜之后下他们的订单,并且可以同时处理多个订单。


它不能做什么?

这里需要注意的一件事是async/await并不是并行/多核编程。当您使用async/await时,只处理该线程,并让其他线程使用它。代码的作用类似于“同步”,因为您可以在await之后以本方法继续执行代码。因此,如果在一个方法中有四个await,则必须等到每个方法都完成后才能调用下一个方法。因此,您必须使用任务库或任何您喜欢的方法生成新线程,以使它们并行运行。但是,您也可以让每个线程使用async/wait,这样它们就不会阻塞资源了!

 

ConfigureAwait(false)能做什么呢?

默认情况下,当您使用async/await时,它将在开始请求的原始线程上继续运行(状态机)。但是,如果当前另一个长时间运行的进程已经接管了该线程,那么你就不得不等待它完成。要避免这个问题,可以使用ConfigureAwait的方法和false参数。当你用这个方法的时候,这将告诉Task它可以在任何可用的线程上恢复自己继续运行,而不是等待最初创建它的线程。这将加快响应速度并避免许多死锁。

但是,这里有一点点损失。当您在另一个线程上继续时,线程同步上下文将丢失,因为状态机改变。这里最大的损失是你会失去归属于线程的Culture和Language,其中包含了国家语言时区信息,以及来自原始线程的HttpContext.Current之类的信息,因此,如果您不需要以此来做多语系或操作任何HttpContext类型设置,则可以安全地进行此方法的调用。注意:如果需要language/culture,可以始终在await之前存储当前相关状态值,然后在await新线程之后重新应用它。

 
以下是ConfigureAwait(false)的示例:

    public async Task<int> ExecuteAsync(UpdateCarCommand request, CancellationToken token = default)	{	using (var context = _contextFactory.Create())	{	var entity = context.Cars.FirstOrDefault(a => a.Id == request.Id);	// Mapping logic	return await context.SaveChangesAsync(token).CongifureAwait(false);	}	}


注意事项

同步 -->异步

如果要使用async/await,需要注意一些事情。您可能遇到的最大问题是处理异步方法请求同步方法。如果你开发一个新项目,通常可以将async/await从上到下贯穿于整个方法链中,而不需要做太多工作。但是,如果你在外层是同步的,并且必须调用异步库,那么就会出现一些有隐患的操作。如果一不小心,便会引发大批量的死锁

如果有同步方法调用异步方法,则必须使用ConfigureAwait(false)如果不这样做,就会立即掉进死锁陷阱。发生的情况是主线程将调用async方法,最终会阻塞这个线程,直到那个async方法完成。然而,一旦异步方法完成,它必须等待原始调用者完成后才能继续。他们都在等待对方完成,而且永远不会。通过在调用中使用configurewait (false), async方法将能够在另一个线程上完成自己操作,而不关心自己的状态机的位置,并通知原始线程它已经完成。进行这个调用的最佳实践如下:

[HttpPut]	
public IActionResult Put([FromBody]UpdateCommand command) =>	_responseMediator.ExecuteAsync(command).ConfigureAwait(false).GetAwaiter().GetResult();


.NET Standard与ConfigureAwait(false)

在.NETCore中,微软删除了导致我们在任何地方都需要ConfigureAwait(false)的SynchronizationContext。因此,ASP.NETCore应用程序在技术上不需要任何ConfigureAwait(false)逻辑,因为它是多余的。但是,如果在开发有一个使用.NETStandard的库,那么强烈建议仍然使用.ConfigureAwait(false)。在.NETCore中,这自动是无效的。但是如果有.NETFramework的人最终使用这个库并同步调用它,那么它们将会遇到一堆麻烦。但是随着.NET5是由.NETCore构建的,所以未来大多都是.NetCore调用.Netstadard,你如果不准备让.NetFramework调用你的standard库,大可不必兼容。
 

ConfigureAwait(false) 贯穿始终

如果同步调用有可能调用您的异步方法,那么在整个调用堆栈的每个异步调用上,您都将被迫设置. configureAwait (false) !如果不这样做,就会导致另一个死锁。这里的问题是,每个async/ await对于调用它的当前方法都是本地的。因此,调用链的每个异async/await都可能最终在不同的线程上恢复。如果一个同步调用一路向下,遇到一个没有configurewait(false)的任务,那么这个任务将尝试等待顶部的原始线程完成,然后才能继续。虽然这最终会让你感到心累,因为要检查所有调用是否设置此属性。
 

开销

虽然async/ await可以极大地增加应用程序一次处理的请求数量,但是使用它是有代价的。每个async/ await调用最终都将创建一个小状态机来跟踪所有信息。虽然这个开销很小,但是如果滥用async/ await,则会导致速度变慢。只有当线程不得不等待结果时,才应该等待它。
 

Async Void

虽然几乎所有的async / await方法都应返回某种类型的Task,但此规则有一个例外:有时,您可以使用async void。但是,当您使用它时,调用者实际上不会等待该任务完成后才能恢复自己。它实际上是一种即发即忘的东西。有两种情况你想要使用它。 
 
第一种情况是事件处理程序,如WPF或WinForms中的按钮单击。默认情况下,事件处理程序的定义必须为void。如果你把一个任务放在那里,程序将无法编译,并且返回某些东西的事件会感觉很奇怪。如果该按钮调用异步async,则必须执行async void才能使其正常工作。幸运的是,这是我们想要的,因为这种使用不会阻塞UI。 
 
第二个是请求你不介意等待获得结果的东西。最常见的示例是发送日志邮件,但不想等待它完成或者不关心它是否完成。 
 
然而,对于这两种情况,都有一些缺点。首先,调用方法不能try/catch调用中的任何异常。它最终将进入AppDomain UnhandledException事件。不过,如果在实际的async void方法中放入一个try catch,就可以有效地防止这种情况发生。另一个问题是调用者永远不会知道它何时结束,因为它不返回任何东西。因此,如果你关心什么时候完成某个Task,那么实际上需要返回一个Task。
 

探讨.NetCore中异步注意事项

在.NetCore中已经剔除了SynchronizationContext,剔除他的主要原因主要是性能和进一步简化操作

在.NetCore中我们不用继续关心异步同步混用情况下,是否哪里没有设置ConfigureAwait(false) 会导致的死锁问题,因为在.netcore中的async/await 可能在任何线程上执行,并且可能并行运行!

以下代码为例:

private HttpClient _client = new HttpClient();	async Task<List<string>> GetBothAsync(string url1, string url2)	
{	var result = new List<string>();	var task1 = GetOneAsync(result, url1);	var task2 = GetOneAsync(result, url2);	await Task.WhenAll(task1, task2);	return result;	
}	async Task GetOneAsync(List<string> result, string url)	
{	var data = await _client.GetStringAsync(url);	result.Add(data);	
}

它下载两个字符串并将它们放入一个List中。此代码在旧版ASP.NET(.NetFramework)中工作正常,由于请求处设置了await,请求上下文一次只允许一个连接.

其中result.Add(data)一次只能由一个线程执行,因为它在请求上下文中执行。

但是,这个相同的代码在ASP.NET Core上是不安全的; 具体地说,该result.Add(data)行可以由两个线程同时执行,而不保护共享List<string>

所以在.Netcore中要特别注意异步代码在并行执行情况下引发的问题


参考:https://stackoverflow.com/questions/31186354/async-await-where-is-continuation-of-awaitable-part-of-method-performed

640?wx_fmt=jpeg


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314832.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【洛谷P5114】八月脸【边分治】【闵可夫斯基和】

题意&#xff1a;一棵 nnn 个点的树&#xff0c;每个点有两个权值 ai,bia_i,b_iai​,bi​&#xff0c;有黑白两种颜色。mmm 次询问&#xff0c;每次给定一个 kkk,求一条端点异色的路径&#xff0c;使得 k∑ai∑bik\sum a_i\sum b_ik∑ai​∑bi​ 最大化。 n≤2105n\leq 2\times…

Educational Codeforces Round 75 (Rated for Div. 2) E2. Voting (Hard Version) 贪心

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; n≤2e5,m≤n,p≤1e9n\le2e5,m\le n,p\le 1e9n≤2e5,m≤n,p≤1e9 思路&#xff1a; 首先需要发现一些性质&#xff0c;假设preipre_iprei​代表所有mj<im_j< imj​<i的pjp_jpj​和。可以发现&#…

【招聘(深圳)】敢为软件技术有限公司 .Net 工程师

敢为软件介绍&#xff1a;深圳市敢为软件技术有限公司致力于打造面向未来的最酷最具影响力的高科技公司。敢为软件在万物互联、行业应用、大屏可视化及自然交互等方面形成完整的闭环&#xff0c;是物联网领域连接能力最强、应用领域最广、用户体验最好的高科技公司。在万物互联…

【WC2018】通道【边分治】【虚树】【树的直径】

题意&#xff1a;给三棵基于同一点集的带边权的树&#xff0c;边权非负&#xff0c;求两点间三棵树上距离之和的最大值。 n≤105n\leq 10^5n≤105 一句话题解&#xff1a;在第一棵树上做边分治&#xff0c;丢到第二棵树上建虚树&#xff0c;在虚树上根据第三棵树的直径dp。 首…

DevOps案例研究:知人善任——Google敏捷核心文化

内容来源&#xff1a;DevOps案例深度研究-Google敏捷实践战队&#xff0c;本文只展示部分PPT及研究成果&#xff0c;更多细节请关注案例分享会。本文内容贡献者&#xff1a;陈霁、刘翀、谈佳婧、张霖。阅读干货前先感受一下热烈的氛围~一、Google如何快速交付原型1.1 Savioke公…

Educational Codeforces Round 111 (Rated for Div. 2) E. Stringforces 二分 + 状压dp

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个串&#xff0c;只包含前kkk个字母和&#xff1f;&#xff1f;&#xff1f;&#xff0c;定义fif_ifi​表示第iii个字母在串中出现的最长连续长度&#xff0c;你现在需要将???替换为前kkk个字母&am…

MTT 学习笔记

很久以前就听说了这东西&#xff0c;一直没空学。最近重学多项式&#xff0c;就重新搞了一下。 MTT 主要解决的是任意模数&#xff08;或者说是没有模数&#xff09;的多项式乘法&#xff0c;可以用于应对专门恶心人的毒瘤题。 首先&#xff0c;假设多项式次数 10510^5105,值…

在 VS Code 中轻松 review GitHub Pull Requests

相信大家在平时工作或者自己的项目中&#xff0c;一定都有在 GitHub 上进行 Code Review 的经历。对于韩老师来说&#xff0c;不论是平时工作的项目&#xff0c;还是自己的业余项目&#xff0c;代码基本都是在 GitHub 上。所以&#xff0c;在 GitHub 上进行 Pull Requests 的 C…

Codeforces Round #732 (Div. 2) C. AquaMoon and Strange Sort 思维

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你nnn个数&#xff0c;每个数初始方向是向右&#xff0c;每次可以交换相邻两个位置并且将这两个位置的方向调换&#xff0c;问这个序列的最终状态能否是非递减且方向都向右。 n≤1e5,ai≤1e5n\le1e5,a_i\l…

【CC November Challenge 2012】Arithmetic Progressions【分块】【FFT】

题意&#xff1a;给定长度为 nnn 的正整数序列 AAA,求满足 i<j<k,Aj−AiAk−Aji<j<k,A_j-A_iA_k-A_ji<j<k,Aj​−Ai​Ak​−Aj​ 的三元组个数。 n≤105,Ai≤3104n\leq 10^5,A_i\leq 3\times 10^4n≤105,Ai​≤3104 三个位置只有 jjj 限制比较紧&#xff0c…

火热的云原生到底是什么?一文了解云原生四要素!

所谓云原生&#xff0c;它不是一个产品&#xff0c;而是一套技术体系和一套方法论&#xff0c;而数字化转型是思想先行&#xff0c;从内到外的整体变革。更确切地说&#xff0c;它是一种文化&#xff0c;更是一种潮流&#xff0c;是云计算的一个必然导向。随着虚拟化技术的成熟…

Codeforces Round #732 (Div. 2) D. AquaMoon and Chess 组合数学 + 找规律

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个010101串&#xff0c;当且仅当某个111的某一边i1,i−1i1,i-1i1,i−1有111&#xff0c;这个111可以跟i2,i−2i2,i-2i2,i−2交换位置&#xff0c;问最终能产生多少状态。 n≤1e5n\le1e5n≤1e5 思路&a…

为什么说拥抱.NET CORE的时候到了

微软和社区已经做了大量艰苦的工作&#xff0c;使.Net Core成为市场上具有竞争力的框架&#xff0c;帮助开发人员快速开发具有最佳性能和可扩展性的强大应用程序。做的最棒的事情是.Net Framework开发人员不需要任何新知识来处理.Net Core。这也是开发人员在很短的时间内采用.N…

【HNOI2016】序列【莫队】【单调栈】【ST表】

题意&#xff1a;给定序列 aia_iai​&#xff0c;qqq 次询问 [l,r][l,r][l,r] 所有子区间最小值之和。 n,q≤105n,q\leq 10^5n,q≤105 这种题一眼看上去是离线线段树&#xff0c;但这题每移动一位要维护区间取 min⁡\minmin&#xff0c;历史值之和&#xff0c;非常不可做。 所…

湖南大学第十六届程序设计竞赛 B Yuki with emofunc and playf 同余最短路

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 初始有一个数111&#xff0c;你每次可以将其∗10*10∗10或者(x−1)(x-1)(x−1)&#xff0c;现在给你xxx&#xff0c;问最少经过多少步能到达nnn。 1≤n≤1e6,1≤m≤1e91\le n\le1e6,1\le m\le1e91≤n≤1e6,1…

【HNOI2019】白兔之舞【组合数学】【矩阵快速幂】【单位根反演】【Chirp Z-Transform】【原根】【MTT】

题意&#xff1a;有一张 (L1)n(L1)\times n(L1)n 个点的有向图&#xff0c;每个结点有二元组 (x,y)(0≤x≤L,1≤y≤n)(x,y)~(0\leq x\leq L,1\leq y\leq n)(x,y) (0≤x≤L,1≤y≤n) 表示。对于所有 (u1,v1),(u2,v2)(u_1,v_1),(u_2,v_2)(u1​,v1​),(u2​,v2​)&#xff0c;若 u…

程序员如何学习英语

首先&#xff0c;这不是一篇广告&#xff0c;虽然这个标题很像。其次&#xff0c;我的英语水平也很一般&#xff0c;所以更多的是谈谈一些失败的经历和思考&#xff0c;俗话说&#xff0c;成功的经验不可复制&#xff0c;失败的经验倒可以让我们少走弯路。英语的重要性毋庸置疑…

Educational Codeforces Round 111 (Rated for Div. 2) D. Excellent Arrays 组合数学

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个数组aia_iai​&#xff0c;定义一个数组是好的当且仅当对于所有iii都有ai!ia_i!iai​!i。定义f(a)f(a)f(a)表示数组aaa中i<j,aiajiji<j,a_ia_jiji<j,ai​aj​ij的(i,j)(i,j)(i,j)对数。定义…

使用Azure云原生构建博客是怎样一种体验?(上篇)

点击上方蓝字关注“汪宇杰博客”导语https://edi.wang我的网站是在.NET Core 平台上使用 C#语言编写的开源博客系统&#xff0c;运行于微软智慧云 Azure 国际版上。本文将重点介绍 Azure 的各项服务如何为博客带来丝滑体验与保驾护航。历史回顾我博客的历史可以追溯到2003年&am…

AtCoder Regular Contest 100 D - Equal Cut 思维 + 前缀和

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个数组aaa&#xff0c;你要将其分成四份&#xff0c;让这四份中和的最大值−-−最小值最小&#xff0c;输出这个最小值。 n≤2e5,ai≤1e9n\le2e5,a_i\le1e9n≤2e5,ai​≤1e9 思路&#xff1a; 直接枚…