简单说说async/await

小明用async/await写了几年的异步方法,但总没有完全理解里面的机制,他决定去请教邻居小花。

小花听了小明的描述后说:首先你要明白异步的根本是什么?大白话解释异步就是:拉一个人(线程)帮着做一些耗时的事(下载、读写数据库等),自己先做别的事了(退出线程),等做好了和我说下,我再继续做后面的事(恢复上下文)。

小花看到小明还没有听明白,就说:我举个简单例子帮你理解吧,假如有两个方法A和B,A调用B方法,B方法是一个异步方法,这时A不等待B执行完,如图:

现在两个方法被分隔几个小块,await关键字其实就用来隔开同步和异步,上面的方法执行流程如下:

A调用B方法后,B方法在未执行到await之前还是同步方法,比如输出Sub1还是在当前线程中执行,当方法遇到await后,就会把await后的方法放到新的线程中执行,当前线程则退出函数,由于调用的地方并没有await,则主线程会继续执行并输出Part2,然后结束。等新线程中Thread.Sleep(5000)执行完后,会执行到Console.Write("Sub2");这一行代码会回到原来的线程执行,其实调用线程在遇到await时会捕获当前线程的执行上下文,然后给到新线程,新线程在执行完耗时操作后,会判断之前捕获到的执行上下方是否为null,如果不为null,则会在上下文中恢复并执行后面的方法,其实就是通过Tak的ContineWith方法注册回调,如图:

小明好像听懂了一些说:现在A方法调用DoSomethingAsync()并没有等待,如果A方法需要这个方法执行完才能继续执行,是不是要在DoSomethingAsync()前面加上await?小花回答是,并说:方法只要遇到await,就会把后面的方法给新线程执行,然后退出线程去执行别的方法,等新线程执行完后再通知当前线程恢复上下文继续执行,如图:

小明又问:你说异步方法执行完后,后面的方法会在原来的线程中恢复并执行,如果我还想在新线程中继续执行剩下的代码,要怎么办呢?小花说问的好,await调用新线程执行耗时操作时默认会捕获当前上下文,如果不想捕获,则可以调用ConfigAwait(false)方法,如图:

执行流程如下:

小花补充到,上线提到的线程1、线程2、线程3等不一定准确,因为异步的回调使用的是线程池中的线程,所以回调有可能还在原来线程中执行,这个主要看操作系统的调度。

小明满意地点点头又问:我经常听同事说用异步方法会死锁,这又是为什么呢?小花听了说,他们肯定是在调用异步方法的时候使用.Result(),如图:

小花指着图解释说:上面的代码task.Result()会阻塞线程并等待task返回结果,DoSomethingAsync方法在执行完Thread.Sleep(5000)后,发现捕获到的上下文不为空,则会尝试将Console.Write("Sub2")这行代码交由调用线程去执行,而这时调用线程还在阻塞等待,就这样互相卡着对方,从而造成了死锁,如图:

小明点了点头又问:那要怎么避免呢?小花说出现这种情况也和框架有关,像WinForm为了让所有UI操作都在主线程中执行,就添加了一个SynchronizationContext类实例用以表示当前上下文,而像控制台等项目这个SynchronizationContext实例默认为null,所以即使使用.Result也不会死锁。但最好使用异步的时候不要用.Result,可以使用ConfigAwait(false)指明不捕获上下文,或所有的方法全部异步到底。

小明听完,拜别了小花,回到了自己的隔间。

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

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

相关文章

Newtonsoft 六个超简单又实用的特性,值得一试 【下篇】

一:讲故事上一篇介绍的 6 个特性从园子里的反馈来看效果不错,那这一篇就再带来 6 个特性同大家一起欣赏。二:特性分析1. 像弱类型语言一样解析 json大家都知道弱类型的语言有很多,如: nodejs,python,php&am…

C++实现双栈结构(一个顺序表中使用两个栈)

因为平常栈中push的数据不会太多&#xff0c;为了节约空间&#xff0c;所以可以在一个顺序表中使用两个栈 结构图: 在这里我会留一个空间用来判断栈是否满&#xff01; #include <iostream> using namespace std; typedef int ElemType;class DoubleStack { private:El…

Redis凭啥这么快?只能做缓存?架构师道出了真相(颠覆你的认知)

Redis到底有多快Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库&#xff0c;由C语言编写&#xff0c;官方提供的数据是可以达到100000的QPS&#xff08;每秒内查询次数&#xff09;。这个数据不比采用单进程多线程的同样基于内存的 KV 数据库 Memcached 差&…

Java面向对象编程(基础部分)

面向对象编程(基础部分) 类与对象 01&#xff1a; public class ObjectWorkDemo {public static void main(String[] args){Cat cat1 new Cat();cat1.name "Tom";cat1.age 3;cat1.color "white";Cat cat2 new Cat();cat2.name "xiaohua"…

Blazor带我重玩前端(一)

写在前面曾经我和前端朋友聊天的时候&#xff0c;我说我希望有一天可以用C#写前端&#xff0c;不过当时更多的是美好的想象&#xff0c;这一切正变得真实……什么是Blazor我们知道浏览器可以正确解释并执行JavaScript代码&#xff0c;那么浏览器是如何执行C#代码的呢&#xff1…

Java面向对象编程(中级)

面向对象编程(中级) 包 访问修饰符 封装 01: public class Encapsulation01 {public static void main(String[] args){Person person new Person();person.name "Tom";person.setAge(30);person.setSalary(30000);} }class Person {public String name;private…

[Mvp.Blazor] 动态路由与钩子函数

&#xff08;Blazor组件的生命周期函数&#xff09;一直在学习也没有停下脚步&#xff0c;用着脑子还是挺好的&#xff0c;感觉可以更脚踏实地一下。最近偶尔也继续看了看Blazor&#xff0c;毕竟我也开源了一个项目嘛&#xff0c;基本我正式开源的项目都会负责到底&#xff0c;…

Java面向对象编程(高级)

面向对象编程(高级) 类变量和类方法 01: package ChildDemo;public class Child {private String name;public static int cnt 0;public Child(String name){this.name name;}public void join(){System.out.println(name "join the game");} }//package ChildDe…

.NET Core + Kubernetes:Volume

和 Docker 类似&#xff0c;Kubernetes 中也提供了 Volume 来实现数据卷挂载&#xff0c;但 Kubernetes 中 Volume 是基于 Pod&#xff0c;而不是容器&#xff0c;它可被 Pod 中多个容器共享&#xff0c;另外 Kubernetes 中提供比较丰富的 Volume 类型[1]&#xff0c;如&#…

WPF中的Data Binding调试指南

点击蓝字“大白技术控”关注我哟加个“星标★”&#xff0c;每日良时&#xff0c;好文必达&#xff01;WPF中的Data Binding如何Debug?大家平时做WPF开发&#xff0c;相信用Visual studio的小伙伴比较多。XAML代码曾经在某些特殊版本的Visual Studio中是可以加断点进行调试的&…

.NET 5 尝鲜 - 开源项目TerminalMACS WPF管理端支持.NET 5

点击上方“Dotnet9”添加关注哦聊天界面设计TerminalMACS一个使用 Prism 作为模块化框架、基于多个开源控件库作为UI控件选择、集成开源 UI 界面设计的 .NET 5 WPF 客户端项目。项目名称&#xff1a;TerminalMACS WPF管理端项目开源地址&#xff1a;Github&#xff1a;https://…

FreeSql.Generator命令行代码生成器是如何实现的

目录FreeSql介绍FreeSql.GeneratorRazorEngine.NetCore源码解析FreeSql.ToolsFreeSqlFreeSql 是功能强大的对象关系映射技术(O/RM)&#xff0c;支持 .NETCore 2.1 或 .NETFramework 4.0 或 Xamarin。有一个强大的ORM&#xff0c;也方便我们开发一个代码生成器。一般情况下&…

Java IDEA断点调试

断点调试(debug) 断点调试应用案例 01&#xff1a; package Assign;public class Debug01 {public static void main(String[] args) {int sum 0;for (int i 0;i<5;i){sumi;System.out.println(i);System.out.println(sum);}System.out.println("continue");} …

.NET Core请求控制器Action方法正确匹配,但为何404?

【导读】提前预祝各位端午节快乐。有时候我们会发现方法名称都正确匹配&#xff0c;但就是找不到对应请求接口&#xff0c;所以本文我们来深入了解下何时会出现接口请求404的情况。匹配控制器Action方法&#xff08;404&#xff09;首先我们创建一个web api应用程序&#xff0c…

布斯乘法以及带符号数的运算

乘法理解 对于最熟悉的十进制乘法很最基本的运算原理就是一个乘数乘以另一个乘数的个位、十位、百位数字然后求和。比如 放到二进制来看其实它也是这样的&#xff0c;多位数的乘法就是一个乘数乘上另一个乘数的各位求和。那么&#xff1a; 布斯算法及原理 原理 已经知道两…

angular 接入 IdentityServer4

angular 接入 IdentityServer4Intro最近把活动室预约的项目做了一个升级&#xff0c;预约活动室需要登录才能预约&#xff0c;并用 IdentityServer4 做了一个统一的登录注册中心&#xff0c;这样以后就可以把其他的需要用户操作的应用统一到 IdentityServer 这里&#xff0c;这…

主机Redis服务迁移到现有Docker Overlay网络

“《麻雀虽小&#xff0c;五脏俱全》之主机现有Redis服务迁移到Docker Swarm Overlay网络&#xff0c;并搭建高可用容器集群。hello, 好久不见&#xff0c;之前文章记录了一个实战的2C分布式项目的改造过程&#xff0c;结果如下&#xff1a;其中Redis并未完成容器化改造&#x…

Java控制结构

控制结构 程序流程控制介绍 顺序控制 分支控制if-else 单分支 案例演示 01: import java.util.Scanner; public class IfWorkDemo {public static void main(String[] args){Scanner myScanner new Scanner(System.in);System.out.println("input your age");int…

.Net Core Configuration源码探究

前言上篇文章我们演示了为Configuration添加Etcd数据源&#xff0c;并且了解到为Configuration扩展自定义数据源还是非常简单的&#xff0c;核心就是把数据源的数据按照一定的规则读取到指定的字典里&#xff0c;这些都得益于微软设计的合理性和便捷性。本篇文章我们将一起探究…

面试官:你说你喜欢研究新技术,那么请说说你对 Blazor 的了解

阅读本文大概需要 1.5 分钟。最近在几个微信 .NET 交流群里大家讨论比较频繁的话题就是这几天自己的面试经历。面试官&#xff1a;“你刚说你喜欢研究新技术&#xff0c;那么你对 Blazor 了解多少&#xff1f;”作为一位专注于 .NET 开发的软件工程师&#xff0c;你好意思说你对…