看过这么多爆文,依旧走不好异步编程这条路?​

点击蓝字

关注我们

本文带大家抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext。

引言

C#异步编程语法糖async/await,使开发者很容易就能编写异步代码。
零散看过很多文章,很多是填鸭式灌输 (有的翻译文还有偏差)。

遵守以上冷冰冰的②③条的原则,一般可确保异步程序按预期运作,

我们时常能在各大论坛看到同学们(因不遵守②③点)引发的死锁现场。

由async/await引起的死锁现场

UI程序(WinForm、WPF):点击按钮,触发一个HTTP请求,用请求结果修改UI控件,以下代码会引发deadlock

public static async Task<string> GetJsonAsync(Uri uri)
{using (var client = new HttpClient()){var jsonString = await client.GetStringAsync(uri);return jsonString;}
}// 上层调用方法
public void Button1_Click(...)
{var jsonTask = GetJsonAsync(...);textBox1.Text = jsonTask.Result;
}

ASP.NET web程序:从api接口发起HTTP请求,返回请求的结果,以下代码也会引发deadlock

public static async Task<string> GetJsonAsync(Uri uri)
{using (var client = new HttpClient()){var jsonString = await client.GetStringAsync(uri);return jsonString;}
}
// 上层调用方法
public class MyController : ApiController
{public string Get(){var jsonTask = GetJsonAsync(...);return jsonTask.Result;}
}

☺️ 解决以上死锁有两种编程方式:

  1. 不再混用异步/同步写法, 始终使用async/await语法糖编写异步代码

  2. 对等待的异步任务应用ConfigureAwait(false)方法

SynchronizationContext就是这类死锁的牛鼻子,大多数时候SynchronizationContext是在异步编程后默默工作,但了解这个对象对于理解sync/await工作原理、解决死锁大有裨益。

本文会解释:

  1. async/await工作机制

  2. SynchronizationContext在异步编程语法糖中的意义

  3. 示例代码为什么会deadlock

1.  await/async语法糖工作机制

微软提出Task线程包装类、 await/async语法糖简化了异步编程的方式:

第②步:调用异步方法GetStringAsync时,开启异步任务;

第⑥步:遇到await关键字,框架会捕获调用线程的同步上下文(SynchronizationContext)对象, 附加给异步任务;同时控制权上交到上层调用函数;

第⑦步:异步任务完成,通过IO完成端口通知上层线程, 第⑧步:通过捕获的线程同步上下文执行后继代码块;

2. SynchronizationContext的意义

先看下MSDN中关于SynchronizationContext的定义:

提供在各种同步模型中传播同步上下文的基本功能。此类实现的同步模型的目的是允许公共语言运行库的内部异步/同步操作使用不同的同步模型正常运行。

☹️这就不是人能看懂的解释,我给出的解释是:在线程切换过程中保存调用线程的上下文环境, 用于在异步任务完成后使用此线程同步上下文执行后继代码。

线程同步上下文的意义在哪?

大家都知道:WinForm和WPF都有类似的原则:长耗时的任务在后台进行,将异步结果返回给UI线程 。(这难道就是ConfigureAwait方法默认传true的原因?)

此时就需要捕获UI线程的SynchronizationContext,并将这个对象传入异步任务。

public static void DoWork()
{//On UI threadvar sc = SynchronizationContext.Current;ThreadPool.QueueUserWorkItem(delegate{//... async task:do work on ThreadPool        sc.Post(delegate{// do work on the original context (UI)}, null);});
}

SynchronizationContext表示代码运行的线程环境,在异步编程中,利用该对象切换代码执行环境。

不同的.NET框架因各自独特的线程切换场景有不同的SynchronizationContext子类(重写父类虚方法):

  • ASP.NET有AspNetSynchronizationContext

  • WinForm有WindowsFormSynchronizationContext

  • WPF 有DispatcherSynchronizationContext

  • ASP.NET Core、控制台程序不存在SynchronizationContext,SynchronizationContext.Current=null

AspNetSynchronizationContext维护了HttpContext.Current、用户身份和文化,但在ASP. NET Core这些信息天然依赖注入,故不再需要SynchronizationContext;另一个好处是不再获取同步上下文对性能也是一种提升。

因此,对于ASP.NET Core程序,ConfigureAwait(false)不是必需的,然而,在基础库时最好还是使用ConfigureAwait(false),因为你保不准上层会混用同步/异步代码。

3. 引言代码为什么发生deadlock

观察引言代码,控制权返回到上层调用函数时,执行流使用Result/(Wait方法)等待任务结果:Result/Wait()导致调用线程同步阻塞(等待任务完成), 而异步任务执行完成后,会尝试利用捕获的同步上下文执行后继代码,这样形成死锁。

正因为如此,我们提出两种方式解决死锁:

  • 原调用函数始终使用await方法,这样调用线程是异步等待任务完成,后继代码可以在该线程同步上下文上执行

  • 对异步任务应用ConfigureAwait(false)方法

ConfigureAwait(bool):true  表示尝试在捕获的原调用线程SynchronizationContext 中执行后继代码;false 不再尝试在捕获的线程SynchronizationContext中执行后继代码。 ConfigureAwait(false)  能解决[因调用线程同步阻塞]引发的死锁,但是同步阻塞没有利用异步编程的优点,不是很推荐。

归根到底,这两种解决死锁的方式都是针对SynchronizationContext
ASP. NET Core和控制台程序,因为捕获的SynchronizationContext=null, 会选择一个线程同步上下文来执行,不会死锁。

总结

微软为加快开发效率上着实费了心力,.NET提供的await/async语法糖简化了异步编程方式,

在异步编程中,SynchronizationContext决定了后继代码在哪里执行的环境,深入理解这个对象的背景和不同框架的实现方式,能帮助我们避免编写死锁代码。

# 更多精彩

  • 面试八股文:你写过自定义任务调度器吗?

  • 你管这叫"线程安全"?

  • 墙裂推荐:这可能是CAP理论的最好解释

  • 全网最通透的“闭包”认知 · 跨越语言

  • 鹅厂二面,Nginx回忆录

  • 实话实说:只会.NET,会让我们一直处于鄙视链、食物链的下游

  • 什么是云原生?

今天因为你的点赞,让我元气满满!

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

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

相关文章

Android获取设备已安装的应用

2019独角兽企业重金招聘Python工程师标准>>> 项目中&#xff0c; 我们经常要用到显示系统已安装的应用&#xff0c; 可以通过两种方式获取已安装的应用&#xff0c; 一种是通过ApplicationInfo, 一种是通过ResolveInfo. 这里用的是ResolveInfo, 上代码。 <!-- la…

如何讲页面打入jar包中_如何把我的Java程序变成exe文件?

JAVA是一种“跨平台”的语言&#xff0c;拥有“一次编写&#xff0c;处处运行”的特点&#xff0c;让它成为当今IT行业&#xff0c;必不可少的一门编程语言。每一个软件开发完成之后&#xff0c;应该大家都需要打包程序并发送给客户&#xff0c;常见的方式&#xff1a;java程序…

Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用

&#xfeff;1622219047536写在前面Api网关我们之前是用 .netcore写的 Ocelot的&#xff0c;使用后并没有完全达到我们的预期&#xff0c;花了些时间了解后觉得kong可能是个更合适的选择。简单说下kong对比ocelot打动我的&#xff1a;1、kong可以直接代替Nginx/OpenRestry做前端…

女生学高铁和计算机哪个更好,2020铁路最好的5个专业 女生上铁路学什么专业好...

铁路专业一直是比较受欢迎的&#xff0c;有些同学都想学习铁路专业&#xff0c;应为一旦找到和铁路相关的工作&#xff0c;工资待遇都是非常好的&#xff0c;但是铁路里面也不是所有的专业都非常好&#xff0c;那么铁路里面最好的专业有哪些呢&#xff1f;女生适合学习铁路的哪…

裤子换裙子,就问你GAN的这波操作秀不秀

全世界只有3.14 % 的人关注了数据与算法之美把照片里的绵羊换成长颈鹿、牛仔长裤换成短裙。听起来有点不可思议&#xff0c;但韩国科学技术院和浦项科技大学的研究人员目前已实现了这一骚操作。他们开发的一种机器学习算法可在多个图像数据集上实现这种操作。其论文《InstaGAN:…

Windows UI风格的设计(11)

转载于:https://blog.51cto.com/8382359/1342271

教之初计算机考试函数应用题,教之初计算机考试系统

教之初计算机考试系统官方版是一款发布长达12年之久的免费考试系统软件&#xff0c;已经有数千万次使用的软件。教之初考试系统是专业的考试软件&#xff0c;您所考虑的功能&#xff0c;教之初都已经非常贴心地替您想好&#xff0c;如果您发现需要的功能并不存在&#xff0c;那…

这里聚集了优秀的数学老师、家长,有超多惊喜在等你!

全世界有3.14 % 的人已经关注了数据与算法之美今天的这篇文章&#xff0c;是向大家推荐一个数学公众号“少年数学家”。“少年数学家”是一个致力为数学老师与家长&#xff0c;提供丰富的数学课外知识、数学人物、数学趣谈、科技与数学的公众号&#xff0c;希望通过这些万物背后…

librosa能量_语音MFCC提取:librosa amp;amp; python_speech_feature(2019.12)

最近在阅读语音方向的论文&#xff0c;其中有个被提及很多的语音信号特征MFCC(Mel-Frequency Cepstral Coefficients)&#xff0c;找到了基于python的语音库librosa(version0.7.1)和python_speech_features(version0.6)&#xff0c;下文对这两个库计算MFCC的流程细节稍作梳理。…

Uno 平台 一 WinUI终极跨平台方案(一)

以下是 Uno 平台的官方介绍&#xff1a;关于 Uno 平台Uno平台能够创建像素级完美的&#xff0c;只通过C#XAML编写的应用程序&#xff0c;能够跨平台运行在Windows&#xff0c;iOS&#xff0c;安卓&#xff0c;macOS&#xff0c;Linux和Web上&#xff0c;Uno 平台是免费和开源的…

Python程序员的30个常见错误

全世界只有3.14 % 的人关注了数据与算法之美在这篇文章中&#xff0c;我将总结新老Python程序员常犯的一些错误&#xff0c;以帮助你们在自己的工作避免犯同样或类似错误。推荐阅读《Python3.0科学计算指南》首先我要说明一下的是&#xff0c;这些都是来源于第一手的经验。我以…

Java程序员从笨鸟到菜鸟之(一百零四)java操作office和pdf文件(二)利用POI实现数据导出excel报表...

在上一篇博客中&#xff0c;我们简单介绍了java读取word&#xff0c;excel和pdf文档内容 &#xff0c;但在实际开发中&#xff0c;我们用到最多的是把数据库中数据导出excel报表形式。不仅仅简单的读取office中的数据.尤其是在生产管理或者财务系统中用的非常普遍&#xff0c;因…

为什么 HTTP3.0 使用 UDP 协议?

还记得以前我提过的常见面试题么&#xff1a;从浏览器地址栏输入网址&#xff0c;到网页彻底打开&#xff0c;中间都发生了什么&#xff1f;从浏览器输入网址&#xff0c;到网页打开&#xff0c;发生了什么&#xff0c;这题有多经典&#xff0c;很多业内技术大牛说用过这题面试…

程序员为啥365天都背电脑包?这答案我服!

全世界只有3.14 % 的人关注了数据与算法之美最近微博上有个最新热门话题“关于报BUG&#xff08;漏洞&#xff09;的礼仪”不要跟程序员说程序有BUG他们第一反应是&#xff1a;你的环境有问题吧&#xff1f;接着就是&#xff1a;XXX你会用吗&#xff01;&#xff08;此处不可描…

html li 做瀑布流,js实现瀑布流效果(自动生成新的内容)

当滚动条接近底部会自动生成新的内容(色块)效果图&#xff1a;代码如下&#xff1a;Title*{list-style: none;}div{overflow: hidden;}ul{float: left;}li{width:300px; margin-bottom:10px;}function rnd(n,m){return parseInt(Math.random()*(m-n))n;}function cl(){var li …

jquery实现多行滚动效果

2019独角兽企业重金招聘Python工程师标准>>> 有时jquery博客想&#xff0c;整那么多demo有什么用呢&#xff1f; 有些前端新手朋友不会&#xff0c;为他们服务吧。还有喜欢自己留点字迹&#xff0c;也好方便自己回过头看看。 温故而知新嘛。 前端需要那么多js特效&a…

.NET 搭建简单的通知服务

搭建简单的通知服务Intro很多情况下&#xff0c;我们都会遇到一些需要进行通知报警的场景&#xff0c;比如说服务器资源监控报警&#xff0c;抢到火车票后通知用户进行付款。原来主要是用的钉钉群里的机器人来做的通知&#xff0c;周末看到原来做 【Server 酱】的大佬写了一个简…

c#程序设计教程 唐大仕pdf_C# 添加PDF水印

概述一般我们在向文档添加水印时&#xff0c;会分为直接添加文字水印和加载图片添加图片水印两种情况。常见的&#xff0c;在添加文字水印时会多以声明文档版权、权威性的文字、标语或者名称等&#xff1b;同样的&#xff0c;图片水印也通常可以是某组织的LOGO、印章、或者其他…

电脑病毒竟然被程序员当宠物养!网友:这些都是我逝去的青春

全世界只有3.14 % 的人关注了数据与算法之美起电脑病毒&#xff0c;大家第一时间应该是想到的熊猫烧香&#xff0c;木马等等吧。很多电脑病毒破坏力惊人&#xff0c;熊猫烧香在当年也是让全国人民都陷入一种恐慌状态。但对于我们程序员来说&#xff0c;看过的病毒跟吃的米一样多…

.NET5 WPF进阶教程

↑↑↑ 点击左上角蓝字关注我&#xff0c;为您提供技术新动态。本期内容一、概要本系列将继《.net wpf快速入门教程》带领大家了解wpf&#xff0c;帮助各位在初级向中级过渡的中掌握基本该具备的能力。本系列视频长度大约在15分钟到30分钟左右&#xff0c;视频内容不仅仅会讲解…