终于明白了 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();
}
(注:上面的代码不是示例,只是因为这段代码而初遇 await Task.Yield)
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() 。
祝大家程序员节快乐!
补充 - 后来发现的相关链接:
终于明白了 C# 中 Task.Yield 的用途的更多相关文章
- await Task.Yield()和await Task.CompletedTask有什么不同
有时候我们在代码中要执行一些非常耗时的操作,我们不希望这些操作阻塞调用线程(主线程)的执行,因为调用线程(主线程)可能还有更重要的工作要做,我们希望将这些非常耗时的操作由另外一个线程去执行,这个时候就 ...
- 初次使用C#中的yield
这几天在Python程序员的微信订阅号中总是见到yield的关键字,才想起来在C#中也是有yield,但是只是知道有,从来没有了解过他的用法,今天有时间就来看看是怎么使用的.刚开始肯定就是搜索一下用法 ...
- Python3中的yield from语法
Python3中的yield from语法 by Kay Zheng Tags: python, 协程, generator 30 March 2014 2016-2-23 更新 這篇文章是兩年前寫的 ...
- 出让执行权:Task.Yield, Dispathcer.Yield
Yield 这个词很有意思,叫做“屈服”“放弃”“让步”,字面意义上是让出当前任务的执行权,转而让其他任务可以插入执行.Task.Dispatcher.Thread 都有 Yield() 方法,看起来 ...
- 15.3 Task Task.Yield和Task.Delay说明
https://blog.csdn.net/hurrycxd/article/details/79827958 书上看到一个Task.Yield例子,Task.Yield方法创建一个立即返回的awai ...
- 【5min+】帮我排个队,谢谢。await Task.Yield()
系列介绍 [五分钟的dotnet]是一个利用您的碎片化时间来学习和丰富.net知识的博文系列.它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的.net ...
- js 中的yield
yield是什么 yield是ES6的新关键字,使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者.它可以被认为是一个基于生成器的版本的return关键字. yield关键字实 ...
- 可惜Java中没有yield return
项目中一个消息推送需求,推送的用户数几百万,用户清单很简单就是一个txt文件,是由hadoop计算出来的.格式大概如下: uid caller 123456 12345678901 789101 12 ...
- SQL Server 2012中Task是如何调度的?
SQL Server 2012中Task是如何调度的?[原文来自:How It Works: SQL Server 2012 Database Engine Task Scheduling] ...
随机推荐
- ajax向Django前后端提交请求和CSRF跨站请求伪造
1.ajax登录示例 urls.py from django.conf.urls import url from django.contrib import admin from app01 impo ...
- pythonのdjango连接MYSQL
在py3.*中利用django使用mysql时,会出现一些问题.由于django默认的是 MySQLdb,但MySQLdb目前不支持py3.*所以我们要改用pymysql,首先要安装pymysql,命 ...
- JavaSE笔记-集合
Java集合大致可分为:List,Set,Map,Queue List:有序,可重复 Set:无序(输出和插入顺序不一定一致),不可重复 Map:映射关系,根据key去访问value Queue:队列 ...
- Ubuntu 16.04下安装MySQL及远程连接
最近因为要研究一个关于MySQL的漏洞,所以需要MySQL的环境,就用了近一个小时的时间搭建了一个,期间出了点问题,故记录于此. 1.首先是安装,在命令窗口中输入下面三条命令即可. sudo apt- ...
- Lua中的表达式
[算术操作符] Lua支持常规的算术操作符有:”+”(加法),”-“(减法),”*”(乘法),”/”(除法),”^”(指数),”%”(取模),一元的”-“(负号).所有的这些操作符都用于实数.例如:x ...
- 【原创】大数据基础之Spark(4)RDD原理及代码解析
一 简介 spark核心是RDD,官方文档地址:https://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-di ...
- vue中html模板使用绑定的全局函数
我们知道在script中使用vue绑定的全局函数时, 我们需要用这种方式使用: this.Util.Fun(e) 那在模板中, 比如v-if中想使用Fun函数怎么办呢?你应该这样做 <i v-i ...
- 微信支付没有结果通知,notify_url参数的接口没有收到微信支付结果通知
在微信支付统一下单的时候需要填一个notify_url参数用于处理微信支付结果通知 但是,有时候我们发现我们设置的这个接口收不到微信请求.原因有一下几个,大家一一对照,也欢迎补充. 1. url是否可 ...
- bat路径中有空格
例如bat文件中写 C:/Program Files (x86)/Google/Chrome/Application/chrome.exe ./html/index.html pause 会报错, ...
- js 在echarts多条折线图数字*100 诡异出现小数
formatter:function(params){ //数据单位格式化 ].name; //x轴名称 , l = params.length; i < l; i++) { if(params ...