终于明白了 C# 中 Task.Yield 的用途
最近在閱讀?.NET Threadpool starvation, and how queuing makes it worse?這篇博文時發(fā)現(xiàn)文中代碼中的一種 Task 用法之前從未見過,在網(wǎng)上看了一些資料后也是云里霧里不知其解,很是困擾。今天在程序員節(jié)的大好日子里終于想通了,于是寫下這篇隨筆分享給大家,也過過專心寫博客的癮。
這種從未見過的用法就是下面代碼中的?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 簡單來說就是創(chuàng)建時就已經(jīng)完成的 Task ,或者說執(zhí)行時間為0的 Task ,或者說是空任務(wù),也就是在創(chuàng)建時就將 Task 的 IsCompeted 值設(shè)置為0。
那 await 一個空任務(wù)會怎樣?我們知道在 await 時會釋放當前線程,等所 await 的 Task 完成時會從線程池中申請新的線程繼續(xù)執(zhí)行 await 之后的代碼,這本來是為了解決異步操作(比如IO操作)霸占線程實際卻用不到線程的問題,而 Task.Yield 卻產(chǎn)生了一個不僅沒有異步操作而且什么也不干的 Task ,不是吃飽了撐著嗎?
今天吃晚飯的時候終于想明白了——吃飽了沒有撐。Task.Yield 產(chǎn)生的空任務(wù)僅僅是為 await 做嫁衣,而真正的圖謀是借助 await 實現(xiàn)線程的切換,讓 await 之后的操作重新排隊從線程池中申請線程繼續(xù)執(zhí)行。這樣做有什么好處呢?線程是非常非常寶貴的資源,千金難買一線程,而且有優(yōu)先級,提高線程利用率的重要手段之一就是及時將線程分配給最需要的地方,而最奢侈的之一是讓一個優(yōu)先級低執(zhí)行時間長的操作一直占用著一個線程,await Task.Yield 可以讓你巧妙地借助 await 的線程切換能力,將不太重要的比較耗時的操作放在新的線程(重新排隊從線程池中申請到的線程)中執(zhí)行。打個比方,很多人排隊在外婆家就餐,你來的時候比較巧,正好有位置,但你本來就不著急肚子也不太餓準備慢慢吃慢慢聊,而排隊的人當中有些人很餓很著急吃完還有事,這時你如果先點幾個招牌菜解解饞,然后將座位讓出來,重新排隊,并且排隊的人當中像你這樣的都這么做,那些排隊中心急如焚的人真是是幸福感爆棚,外婆家的老板也笑彎了腰。你讓出座位重新排隊的愛心行為就是?await Task.Yield()。
祝大家程序員節(jié)快樂!
補充 - 后來發(fā)現(xiàn)的相關(guān)鏈接:
出讓執(zhí)行權(quán):Task.Yield, Dispatcher.Yield:?https://walterlv.com/post/yield-in-task-dispatcher.html?
原文地址:?https://www.cnblogs.com/dudu/p/task-yield.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的终于明白了 C# 中 Task.Yield 的用途的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MonkeyFest2018 微软最有价
- 下一篇: c# 弹性和瞬态故障处理库Polly 学