C# await 高级用法
原文:C# await 高级用法 本文告诉大家 await 的高级用法,包括底层原理。 昨天看到太子写了一段代码,我开始觉得他修改了编译器,要不然下面的代码怎么可以编译通过 需要知道,基本可以添加 await 都是可以等待的类型,如 Task 。如果一个类需要可以被等待,那么这个类必须满足以下条件 类里有一个 GetAwaiter 函数 GetAwaiter 有返回值,返回值需要继承 INotifyCompletion 并且有 参见:如何实现一个可以用 await 异步等待的 Awaiter - walterlv 但是上面的代码使用的是一个字符串,什么时候可以修改继承字符串? 先让我来说下 await 原理,因为知道了原理,上面的代码实现很简单。看完了本文,你就会知道如何让几乎所有类型包括 int 、string 、自定义的类都支持 await 。 如果真的不想看原理,那么请直接调到文章的最后,看到最后很快就知道如何做。 在 .net 4.5 之后,框架默认提供 async 和 await 的语法糖,这时千万不要认为进入 await 就会进入一个新的线程,实际上不一定会进入一个新的线程才会调用 await 。 那么 await 的语法糖写的是什么?实际上就是以前的 Begin xx 和 End xx 的语法糖。 古时候的写法: 这样大家就无法在一个流程写完,需要分为两个东西,而在 Continus with 下,就需要传入委托。如果委托里又使用了异步,那么又需要传入委托 所以这时就使用了 await ,可以让大家按照顺序写。 实际上 await 是在编译时支持的,请看进阶篇:以IL为剑,直指async/await - 布鲁克石 - 博客园 而且千万不要认为 await 一定会进入一个新的线程,实际上他只是把需要写在多处的代码,可以按照流写下载,和写同步代码一样。如果感兴趣 await 不一定会进入一个新的线程请看 There Is No Thread 因为 await 需要找到一个 GetAwaiter 函数,这个函数即使是扩展方法也可以,所以其实上面的代码是这样写的 HeabdsdnbKevx 就是一个可以等待的类型 现在就可以写出下面的代码 当然,上面的这个代码可以运行,不过不会返回什么。下面让我加上一句代码。 这时可以看到, 但是作为一个挖坑专业的大神,怎么可以就扩展 string ,下面我把 int 进行扩展 随意写一个值,然后进行等待 现在我准备在 object 加一个扩展方法,所有类型都可以等待,然后把这个扩展方法的 namespace 写为 System ,这样大家就不知道这个是我写的,过了一年我就告诉大家这是 C# 的特性,所有的类都可以等待。但是这个特性需要开光才可以使用,你们直接建的项目没有开光所以没法使用这个特性。 虽然很多时候从原理上看,等待和不等待只是调用时机的问题。但是依旧遇到一些小伙伴一直以为全部的异步方法都需要 下面的代码是最常见的代码,在 例如我这样写 输出就是按照顺序输出 如果我修改一下代码,创建一个新的函数 但是不在调用 就是这样的代码,我的小伙伴说,这样写不清真,实际上这样写也是清真的代码。在调用 但是不加 await 的呢?也就是函数一直都没有等待,我再写一个函数 调用的时候没有等待 这时会在输出 这样和使用 void 函数有什么区别? 在执行的函数遇到第一个 输出下面代码 不是所有的 await 都会开多线程,如下面的代码 也就是在没有 本文会经常更新,请阅读原文:
await "林德熙逗比";
bool IsCompleted { get; },GetResult(),void OnCompleted(Action continuation) 定义原理
foo.Beginxx();
foo.Endxx(传入委托);
task.ContinueWith(_ =>
{
Task t1 = new Task(() => { });
t1.ContinueWith((t2) =>
{
//可以看到如果进入很多的委托
});
});
await task;
Task t1 = new Task(() => { });
await t1;
//可以看到这时不需要进入委托
使用
public static class KvpbamjhKsvm
{
public static HeabdsdnbKevx GetAwaiter(this string str)
{
return new HeabdsdnbKevx();
}
}
public class HeabdsdnbKevx : INotifyCompletion
{
public bool IsCompleted { get; }
public void GetResult()
{
}
/// <inheritdoc />
public void OnCompleted(Action continuation)
{
}
}
private static void Main(string[] args)
{
DdngSiwchjux();
}
private static async void DdngSiwchjux()
{
await "林德熙逗比";
}
private static void Main(string[] args)
{
DdngSiwchjux();
}
private static async void DdngSiwchjux()
{
await "林德熙逗比";
Console.WriteLine("csdn");
}
Console.WriteLine("csdn");不会运行,因为这时如果在 OnCompleted 函数打断点就可以看到,执行await "林德熙逗比"之后就进入OnCompleted 函数。从上面的原理可以知道,这个函数传入的参数就是两个await或 await和函数结束之间的代码。如果需要让Console.WriteLine("csdn");运行,那么只需要在OnCompleted运行参数
public void OnCompleted(Action continuation)
{
continuation();
}

public static class KvpbamjhKsvm
{
public static HeabdsdnbKevx GetAwaiter(this int dxpbnzSce)
{
return new HeabdsdnbKevx();
}
}

等待和不等待的区别
await,看到我写了没有直接await的代码觉得很诡异,所以我在这里做个实验给大家看。async Task 的方法使用 await ,这样就会等待这个方法完成,代码就和同步代码一样。 await GagarLerecel();
private static async Task GagarLerecel()
await GagarLerecel();
private static async Task GagarLerecel()
{
Write("GagarLerecel 开始");
await Task.Delay(100);
Write("GagarLerecel 完成");
}
GagarLerecel 开始
GagarLerecel 完成
CoujafuDarso 里面的代码和上面函数相同 private static async Task CoujafuDarso()
{
Write("CoujafuDarso开始");
await Task.Delay(100);
Write("CoujafuDarso结束");
}
CoujafuDarso 使用 await ,而是使用一个变量 var aa = CoujafuDarso();
Write("其他代码");
await aa;
CoujafuDarso 会在代码到第一个 await 函数就返回,于是先执行了CoujafuDarso开始,然后函数返回,执行Write("其他代码"),在最后await aa才等待函数把所有代码执行完成。所以可以看到下面输出CoujafuDarso开始
其他代码
CoujafuDarso结束
BotujawWorpay private static async Task BotujawWorpay()
{
Write("BotujawWorpay开始");
await Task.Delay(100);
Write("BotujawWorpay结束");
}
BotujawWorpay();
Write("CesearJemmeme");
CesearJemmeme之后,某个时间继续执行函数BotujawWorpay开始
CesearJemmeme
BotujawWorpay结束
await 就会返回,这样就可以继续执行函数下面的代码
德熙逗比代码
BarpooseewhowGelpousacall 代码1 线程1
德熙逗比状态开始
BarpooseewhowGelpousacall 代码2 线程5
BarpooseewhowGelpousacall 代码3 线程4
BarpooseewhowGelpousacall 完成 线程5
多线程
static void Main(string[] args)
{
Write("开始");
Write("线程" + Thread.CurrentThread.ManagedThreadId);
CeaXisci();
Task.Run(async () =>
{
await Task.Delay(1000);
MouvaypuNasjo();
});
while (true)
{
Console.Read();
}
}
private static async Task BarpooseewhowGelpousacall()
{
Write("BarpooseewhowGelpousacall 代码1 线程" + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(10);
Write("BarpooseewhowGelpousacall 代码2 线程" + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(10);
Write("BarpooseewhowGelpousacall 完成 线程" + Thread.CurrentThread.ManagedThreadId);
}
Task.Delay分开的代码,只要使用了 await 那么就可以在同个线程运行,请看输出。在最后的BarpooseewhowGelpousacall 完成和这个函数后面的代码都在同一个线程运行,而上面的代码,可能是在同个线程,也可能在不同的线程开始
线程1
CeaXisci 开始 线程1
BarpooseewhowGelpousacall 代码1 线程1
BarpooseewhowGelpousacall 代码2 线程5
BarpooseewhowGelpousacall 完成 线程4
CeaXisci 开始 完成4
相关博客
https://lindexi.gitee.io/lindexi/post/C-await-%E9%AB%98%E7%BA%A7%E7%94%A8%E6%B3%95.html
,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用
知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议
进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:
https://lindexi.gitee.io
),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请
与我联系
。
C# await 高级用法的更多相关文章
- Fiddler高级用法
Fiddler高级用法 1. 简单用法 Fiddler作为一个基于http协议的抓包工具,一直在业界有广泛使用.很多测试或者前端在使用Fiddler时,仅仅用于查看前端和服务端之间的请求信息.包括我作 ...
- Visual Studio 宏的高级用法
因为自 Visual Studio 2012 开始,微软已经取消了对宏的支持,所以本篇文章所述内容只适用于 Visual Studio 2010 或更早期版本的 VS. 在上一篇中,我已经介绍了如何编 ...
- SolrNet高级用法(分页、Facet查询、任意分组)
前言 如果你在系统中用到了Solr的话,那么肯定会碰到从Solr中反推数据的需求,基于数据库数据生产索引后,那么Solr索引的数据相对准确,在电商需求中经常会碰到菜单.导航分类(比如电脑.PC的话会有 ...
- sqlalchemy(二)高级用法
sqlalchemy(二)高级用法 本文将介绍sqlalchemy的高级用法. 外键以及relationship 首先创建数据库,在这里一个user对应多个address,因此需要在address上增 ...
- Solr学习总结(六)SolrNet的高级用法(复杂查询,分页,高亮,Facet查询)
上一篇,讲到了SolrNet的基本用法及CURD,这个算是SolrNet 的入门知识介绍吧,昨天写完之后,有朋友评论说,这些感觉都被写烂了.没错,这些基本的用法,在网上百度,资料肯定一大堆,有一些写的 ...
- 再谈Newtonsoft.Json高级用法
上一篇Newtonsoft.Json高级用法发布以后收到挺多回复的,本篇将分享几点挺有用的知识点和最近项目中用到的一个新点进行说明,做为对上篇文章的补充. 阅读目录 动态改变属性序列化名称 枚举值序列 ...
- Jquery remove 高级用法
Jquery remove 高级用法 html 代码 <div class="file-image">abc1111</div><div class= ...
- Newtonsoft.Json高级用法(转)
手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数 ...
- redis(二)高级用法
redis(二)高级用法 事务 redis的事务是一组命令的集合.事务同命令一样都是redis的最小执行单元,一个事务中的命令要么执行要么都不执行. 首先需要multi命令来开始事务,用exec命令来 ...
随机推荐
- Qt的焦点策略
Qt的窗口部件在图形用户界面中按用户的习惯的方式来处理键盘焦点.基本出发点是用户的击键能定向到屏幕上窗口中的任何一个,和在窗口中任何一个部件中.当用户按下一个键,他们期望键盘焦点能够到达正确的位置,并 ...
- C语言深度剖析-----多维数组和多维指针
多维数组和多维指针 指向指针的指针 指针变量同样也有传址调用和传值调用 case1:估算要5个字节的空间,实际只用前面3个字节,设计释放空的2字节 case2:扩充到10字节 二维数组与二维指针 二维 ...
- 使用wepy开发微信小程序商城第三篇:购物车(布局篇)
使用wepy开发微信小程序商城 第三篇:购物车(布局篇) 前两篇如下: 使用wepy开发微信小程序商城第一篇:项目初始化 使用wepy开发微信小程序商城第二篇:路由配置和页面结构 基于上两篇内容,开始 ...
- P2P平台的"我要借款"功能,是否需要上传借款人的相关资料
P2P平台的前端系统,一般都会有"我要借款"这个功能.有的平台,非常重视这个功能, 把它作为主要菜单的其中一项.有的把它看得相对次要,放在顶部Top栏中. 毕竟P2P平台,其实主 ...
- Maven基础教程 分类: C_OHTERS 2015-04-10 22:53 232人阅读 评论(0) 收藏
更多内容请参考官方文档:http://maven.apache.org/guides/index.html 官方文档很详细,基本上可以查找到一切相关的内容. 另外,快速入门可参考视频:孔浩的maven ...
- 判断客户端是iPad、安卓还是ios
武穆逸仙 有人心疼时,眼泪才是眼泪,否则只是带着咸味的液体:被人呵护着,撒娇才是撒娇,要不然就是作死. 努力做一个可爱的人,不埋怨谁,不嘲笑谁,也不羡慕谁,阳光下灿烂,风雨中奔跑,做自己的梦,走自己的 ...
- NASM Syntax
NASM has a simplified syntax designed to let the user code with minimum overhead. In its simplest fo ...
- css3-11 网页如何使用自定义字体
css3-11 网页如何使用自定义字体 一.总结 一句话总结:下载好字体文件,然后在网页中引入,用src: url('my.otf');来引入,使用的时候就使用自己定义的名字来使用这个字体. 1.网页 ...
- 初步安装git使用命令配置电脑中的git关联的账户
原文地址 https://www.jianshu.com/p/39684a3ad4fa 出现问题 当我们初步使用git的时候,会报一些出乎预料的错误,比如:报错:fatal: unable to au ...
- 手把手生成决策树(dicision tree)
手把手生成决策树(dicision tree) 标签: Python 机器学习 主要參考资料: Peter HARRINGTON.机器学习实战[M].李锐,李鹏,曲亚东,王斌译.北京:人民邮电出版社, ...