在.NET中执行Async/Await的两种错误方法

微信公众号:架构师高级俱乐部
关注可了解更多的编程,架构知识。问题或建议,请公众号留言;
如果你觉得此文对你有帮助,欢迎转发

在.NET中执行异步/等待的两种错误方法

在应用开发中,我们为了提高应用程序的吞吐能力或者异步操作来减少耗时,通常会使用多线程来达到目的,而在C#语言中由于async/await必杀技的存在,大多会使用此来简化多线程操作,async/await的具体使用方式想必大家已烂熟于心,不再赘述,今天主要谈谈在我们经常所谓的async/await操作真的是正确的吗?你又真的用对他了吗?

情景1:消除异步方法优势

请看下面代码示例

ServiceClient client = new ServiceClient();
ServiceRequest request = new ServiceRequest();
request.Id = newId;            
var responseTask = Task.Run(() => client.GetServicesAsync(request));
ServiceResponse response = await responseTask;

以上代码片段在一个异步方法中,此方法在另一个Task中返回一个Task!(Task.Run) 这是多余的。如果该方法已经返回Task,则我们不应该将其包装在另一个Task中。因此,在这种情况下,解决方案也非常简单,取消一切不必要的Task:

ServiceClient client = new ServiceClient();
ServiceRequest request = new ServiceRequest();
request.Id = newId;            
var responseTask = client.GetServicesAsync(request);
ServiceResponse response = await responseTask;

情景2:滥用Task.Run()

在工作中大多使用Task.Run的代码给人的印象是异步有助于提高性能。这是正确的,但仅是非常片面的。Async/Await的目的是帮助提高吞吐量。改善性能仅仅是副作用。

因此在工作中会发现各种奇奇怪怪的代码,例如以下为了配合外部异步方法,又由于内部各种原因没有实现异步方法,不得不用Task.Run来包裹同步方法而达到语法要求。

MyService client = new MyService();
var responseTask = Task.Run(() => client.GetData(request));
var response = await responseTask;

换句话说:使用Task.Run()包装了一个同步调用。

这里的问题是方法client.GetData()本身并不是异步方法,通过将异步包装器置于同步方法之上,我们正在做一个称为“async-over-sync异步超同步”的反模式,这在大多数情况下最终不是一个推荐的做法。不是因为它不起作用(而是起作用),而是因为它效率不高。

之所以如此,原因是很长的,而且涉及很多,如果感兴趣可在文章末尾找到Stephen作者相关对此问题的详细解释地址[1]。总结一下,以上代码非常糟糕,因为实现异步的好处是通过在线程不执行任何操作(例如,等待服务响应)时“释放”线程来提高吞吐量。上面的示例确实释放了一个线程,它也立即消耗了另一个线程来执行任务包装的代码,并且该消耗的线程在等待服务响应时被阻塞。因此,我们没有提高吞吐量,只是将工作从一个线程转移到了另一个线程。而且在并发下,以上使用方式在工作中也极大的降低了系统性能!


解决方案可以简化为:不要对同步方法使用异步包装器!只需同步调用它们即可。在这种情况下,理论上的性能优势将被潜在的问题所抵消,这些潜在的问题在最坏的情况下可能包括死锁。

过度使用Task.Run()有很大安全隐患,尤其在你未搞懂你写了什么的时候,这种影响在复杂业务和超大并发下出问题非常难排查!在发现性能严重影响又找不到原因的时候,请排查出所有使用Task.Run的代码,确定是否是以上两种情况,解决他们可能就海阔天空了

摘要

在.NET或者.Netcore中使用Async/Await都是一项技巧,必须谨慎使用。在上面的示例中,开发团队试图使他们的应用程序性能更好,但最终由于对他们的代码过度使用Async/Await而使情况变的难以控制。

总之应该记住两件事:

不要将异步任务包装在另一个异步包装器Task.Run中。

不要在同步调用上使用异步包装器。

有很多方法可以修正使用异步/等待的ASP.NET代码。



更多请参考

[1]:https://devblogs.microsoft.com/pfxteam/should-i-expose-asynchronous-wrappers-for-synchronous-methods/(我应该为同步方法加异步包装器Task.Run吗)

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

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

相关文章

C#如何安全、高效地玩转任何种类的内存之Span的秉性特点(二)

前言读完上篇《C#如何安全、高效地玩转任何种类的内存之Span的本质(一)》,相信大家对span的本质应该非常清楚了。含着金钥匙出生的它,从小就被寄予厚望要成为.NET下编写高性能应用程序的重要积木,而且很多老前辈为了接纳它,都纷纷…

word List 05

word List 05 如果存在什么问题,欢迎批评指正!谢谢!

《ASP.NET Core 微服务实战》-- 读书笔记(第6章)

第 6 章 事件溯源与 CQRS在本章,我们来了解一下随着云平台一同出现的设计模式我们先探讨事件溯源和命令查询职责分离(CQRS)背后的动机与哲学事件溯源简介事实由事件溯源而来我们大脑就是一种事件溯源系统,接收感官多种形式刺激&am…

数据结构----快速排序

数据结构----快速排序 原理&#xff1a;参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> int quickSort(int a[], int l, int h) {//快速排序int i l, j h, p a[l];while (i < j) {while (i<j&&a[j]>p) {//从右往左…

编译调试 .NET Core 5.0 Preview 并分析 Span 的实现原理

很久没有写过 .NET Core 相关的文章了&#xff0c;目前关店在家休息所以有些时间写一篇新的????。这次的文章主要介绍如何在 Linux 上编译调试最新的 .NET Core 5.0 Preview 与简单分析 Span 的实现原理。微软从 .NET Core 5.0 开始把 GIT 仓库 coreclr 与 corefx 合并移动…

数据结构----归并排序

数据结构----归并排序 原理&#xff1a;参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> #define N 100 void guiBingSort(int a[], int l, int h,int length) {//归并排序int mid (l h) / 2;int* b (int *)malloc(N*sizeof(int));i…

利用obfuscar对.NET应用进行混淆

背景发布客户端程序产品时&#xff0c;免不了会遇到一些怀有恶意或有强烈学习欲望的用户尝试对程序进行反编译。对于一些编译成本地指令的程序&#xff08;如C、C&#xff09;&#xff0c;编译后可读性低&#xff0c;反编译和破解成本较高&#xff0c;不需要对代码进行太高强度…

数据结构---基数排序

数据结构—基数排序 原理&#xff1a;参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> int getNumberBit(int number) {//获取数字的位数int x number,count0;if (x 0)return 1;while (x ! 0) {count;x / 10;}return count; } int g…

C# 版本 疫情传播仿真程序

前言前一阵子看到有人制作了《疫情传播仿真程序》&#xff0c;是用 Java做的。里面根据多种实际情况&#xff0c;如居民移动意愿、医护能力、病毒传播能力&#xff0c;来模拟疫情的发展。看完之后&#xff0c;我暗暗称奇&#xff0c;特别是结合一些视频和照片&#xff0c;确实做…

jmeter 加密解密_使用Jmeter对SHA1加密接口进行性能测试

机会只留给那些有准备的人改变能改变的&#xff0c;接受不能改变的&#xff0c;就是进步性能测试过程中&#xff0c;有时候会遇到需要对信息头进行加密鉴权&#xff0c;下面我就来介绍如何针对SHA1加密鉴权开发性能测试脚本 1、首先了解原理&#xff0c;就是需要对如下三个参数…

word List 06

word List 06 如果存在什么问题&#xff0c;欢迎批评指正&#xff01;谢谢&#xff01;

面对疫情,在家办公的程序员如何突围

作者&#xff1a;陌北有棵树&#xff0c;架构师社区合伙人很多程序员朋友都已经开始了在家办公的生活&#xff0c;第一天办公&#xff0c;你的远程工具还流畅吗&#xff0c;视频会议换了几个软件&#xff1f;当然这些都是外在因素&#xff0c;尤其对于程序员来说&#xff0c;解…

[蓝桥杯2018初赛]全球变暖-dfs,bfs,连通块

解题思路: bfs:遍历所有未遍历过的陆地&#xff0c;通过bfs计算出当前位置连通陆地的数量cnt&#xff0c;以及被淹没陆地的数量bound,若cnt bound表示完整淹没的一个岛屿 dfs:将连通块全部标记&#xff0c;如果这个连通块全部都会淹没&#xff0c;则答案1&#xff0c;如果这个…

latex 参考文献显示问号_回「LaTeX 的罪与罚」

原文链接&#xff1a;LaTeX 的罪与罚 - 朴素的贝叶斯的文章 - 知乎作为 LaTeX 开发者&#xff0c;看到这种嘲讽自然是非常 angry 的。本来并不想趟这个混水&#xff0c;然而眼见着赞数一天天涨上去&#xff0c;还居然进了精华区&#xff0c;实在忍不住只好注册了贵乎来说几句。…

疫情之下,使用FRP实现内网穿透,远程连接公司电脑进行办公

当前情况下&#xff0c;经常会有需要到公司电脑进行一些操作&#xff0c;比如连接内网OA&#xff0c;数据库或者提交文档。为了减少外出&#xff0c;将使用frp进行内网穿透的方法进行一个说明。前提条件1. 一台拥有公网 IP 的设备(如果没有&#xff0c;服务器可以使用https://d…

ad中电容用什么封装_二极管在电路中到底做什么用的

所有的电子电路中基本上都会用到二极管&#xff0c;它的特性也是非常之多&#xff0c;最主要就是单方向导电性&#xff0c;(单向导电性的两根引脚之间的电阻分为正向电阻和反向电阻两种)。人们利用这些不同特性构成各种具体的应用电路&#xff0c;分析不同电路中的二极管工作原…

数据结构---邻接矩阵的DFS

数据结构—邻接矩阵的DFS 原理&#xff1a;参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> #define N 100 #define elemType int //const int MAX_INT (1 << 31) - 1; //const int MAX_INT 0X7fffffff; #define INF (((uns…

.NET Core 如何判断程序是否在远程桌面(RDP)下运行

点击上方蓝字关注“汪宇杰博客”导语由于疫情的关系&#xff0c;很久没发文章了。今天终于稳定下来在家办公&#xff0c;抽空分享一个刚学会的技巧。最近在家办公的程序员可能避免不了要用远程桌面&#xff0c;那么问题来了&#xff0c;你的 .NET Core 程序有没有办法知道自己是…

[蓝桥杯2018初赛]方格计数-巧妙枚举,找规,数论

解题思路&#xff1a; 枚举第一象限的所有点&#xff0c;判断是否在圆内&#xff0c;最后结果*4 我们用下面的程序&#xff0c;来算一个半径为2的圆&#xff0c;其实我们第一象限算的就是那个绿点&#xff0c;然后类比到半径5000. 代码如下&#xff1a; #include <iostre…

ipa在线安装搭建_三种越狱工具安装方法

从 iOS 9.2 开始&#xff0c;苹果越狱进入了半越狱时代&#xff0c;也就是重启手机之后需要重新进入越狱工具激活越狱环境&#xff0c;以下是三种常用的越狱工具安装方法&#xff1a;方法一&#xff1a;自签名下载大胡子签名工具&#xff1a;Cydia Impactor下载地址&#xff1a…