终于明白了 C# 中 Task.Yield 的用途
最近在阅读 .NET Threadpool starvation, and how queuing makes it worse 这篇博文时发现文中代码中的一种 Task 用法之前从未见过,在网上看了一些资料后也是云里雾里不知其解,很是困扰。今天在程序员节的大好日子里终于想通了,于是写下这篇随笔分享给大家,也过过专心写博客的瘾。
这种从未见过的用法就是下面代码中的 await Task.Yield()
:
static async Task Process() { await Task.Yield(); var tcs = new TaskCompletionSource<bool>(); Task.Run(() => { Thread.Sleep(1000); tcs.SetResult(true); }); tcs.Task.Wait(); }
Task.Yield 简单来说就是创建时就已经完成的 Task ,或者说执行时间为0的 Task ,或者说是空任务,也就是在创建时就将 Task 的 IsCompeted 值设置为0。
那 await 一个空任务会怎样?我们知道在 await 时会释放当前线程,等所 await 的 Task 完成时会从线程池中申请新的线程继续执行 await 之后的代码,这本来是为了解决异步操作(比如IO操作)霸占线程实际却用不到线程的问题,而 Task.Yield 却产生了一个不仅没有异步操作而且什么也不干的 Task ,不是吃饱了撑着吗?
今天吃晚饭的时候终于想明白了——吃饱了没有撑。Task.Yield 产生的空任务仅仅是为 await 做嫁衣,而真正的图谋是借助 await 实现线程的切换,让 await 之后的操作重新排队从线程池中申请线程继续执行。这样做有什么好处呢?线程是非常非常宝贵的资源,千金难买一线程,而且有优先级,提高线程利用率的重要手段之一就是及时将线程分配给最需要的地方,而最奢侈的之一是让一个优先级低执行时间长的操作一直占用着一个线程,await Task.Yield 可以让你巧妙地借助 await 的线程切换能力,将不太重要的比较耗时的操作放在新的线程(重新排队从线程池中申请到的线程)中执行。打个比方,很多人排队在外婆家就餐,你来的时候比较巧,正好有位置,但你本来就不着急肚子也不太饿准备慢慢吃慢慢聊,而排队的人当中有些人很饿很着急吃完还有事,这时你如果先点几个招牌菜解解馋,然后将座位让出来,重新排队,并且排队的人当中像你这样的都这么做,那些排队中心急如焚的人真是是幸福感爆棚,外婆家的老板也笑弯了腰。你让出座位重新排队的行为就是 await Task.Yield()
。
祝大家程序员节快乐!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
1024程序员节 | 阿里巴巴集团开源软件巡礼(史上最全)
小蚂蚁说: 开源先锋Tim O'Reilly 先生曾言:“开源软件是计算机工业最宝贵的财富”。阿里巴巴是开源社区积极的共建者,为开源软件发展做了重要的贡献,相关的 GitHub 2017年数据统计显示,阿里巴巴是唯一一家入围 GitHub 顶尖贡献名单的中国公司,值此1024程序员节,我们梳理阿里巴巴集团的重要开源项目,希望能给对大家有所帮助。 回顾更多蚂蚁金服相关的开源信息: 《开源 |蚂蚁金服启动分布式中间件开源计划,用于快速构建金融级云原生架构》 《蚂蚁金服开源:数据驱动的高交互可视化图形语法G2》 《开源 | 蚂蚁金服分布式中间件开源第二弹:丰富微服务架构体系》 《开源 | 蚂蚁金服开源:关系数据的可视化引擎 G6 2.0》…… 目录 一、前言 二、前端 三、Java 四、数据库 五、系统 六、教程 一、前言 程序员的语言是代码,程序员的交流工具就是开
- 下一篇
JavaScript原型链和继承
1.概念 JavaScript并不提供一个class的实现,在ES6中提供class关键字,但是这个只是一个语法糖,JavaScript仍然是基于原型的。JavaScript只有一种结构:对象。每个对象都有一个私有属性:_proto_,这个属性指向它构造函数的原型对象(property)。它的原型对象也有一个属于自己的原型对象,这样层层向上只至这个原型对象的属性为null。根据定义null没有自己的原型对象,它是这个原型链中的最后一个环节。 几乎所有的JavaScript中的对象都是位于原型链顶端的Object的实例。 2.基于原型链的继承 JavaScript对象是动态的属性“包”(指其自己的属性)。JavaScript对象有一个指向原型对象的链。当访问一个对象的属性时,它不仅仅在对象上搜寻,还会试图搜寻对象的原型,以及该对象原型的原型,依次层层向上搜索,直至找到一个名字匹配的属性或者到达原型链的顶端为止。 在ECMA标准中,someObject.[[Prototype]]符号是表示指向someObject的原型。从ES6开始[[Prototype]]可以通过Object.getPr...
相关文章
文章评论
共有0条评论来说两句吧...