溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C#中怎么使用Task.Yeild()函數(shù)

發(fā)布時(shí)間:2020-07-15 15:35:05 來源:億速云 閱讀:208 作者:小豬 欄目:開發(fā)技術(shù)

這篇文章主要講解了C#中怎么使用Task.Yeild()函數(shù),內(nèi)容清晰明了,相信大家閱讀完之后會(huì)有幫助。

      在與同事討論async/await內(nèi)部實(shí)現(xiàn)的時(shí)候,突然想到Task.Yeild()這個(gè)函數(shù),為什么呢,了解一點(diǎn)C#async/await內(nèi)部機(jī)制的都知道,在await一個(gè)異步任務(wù)(函數(shù))的時(shí)候,它會(huì)先判斷該Task是否已經(jīng)完成,如果已經(jīng)完成,則繼續(xù)執(zhí)行下去,不會(huì)返回到調(diào)用方,原因是盡量避免線程切換,因?yàn)閍wait后面部分的代碼很可能是另一個(gè)不同的線程執(zhí)行,而Task.Yeild()則可以強(qiáng)制回到調(diào)用方,或者說主動(dòng)讓出執(zhí)行權(quán),給其他Task執(zhí)行的機(jī)會(huì),可以把Task理解為協(xié)程,Task.Yeild()和Thread.sleep(0)有點(diǎn)相同。

      為了證明我的結(jié)論成立,請(qǐng)看代碼:

public static async Task Test1()
{
   await Task.CompletedTask;
   Thread.Sleep(1000);
   Console.WriteLine("Test1任務(wù)完成");
}
public static async Task Test2()
{
   await Task.Delay(1);
   Thread.Sleep(1000);
   Console.WriteLine("Test2任務(wù)完成");
}
public static async Task Test3()
{
   await Task.Yield();
   Thread.Sleep(1000);
   Console.WriteLine("Test3任務(wù)完成");
}
static void Main(string[] args)
{
   Console.WriteLine(DateTime.Now);
   _ = Test1();
   Console.WriteLine(DateTime.Now);
   Console.ReadLine();
}

      按照開頭的理論,Test1()異步函數(shù)由于await了一個(gè)已經(jīng)完成的任務(wù),所以會(huì)繼續(xù)往下執(zhí)行,阻塞1秒鐘,然后回到調(diào)用方,打印的時(shí)間之差會(huì)相隔一秒。

C#中怎么使用Task.Yeild()函數(shù)

      Test2()異步函數(shù)由于await了一個(gè)未完成的任務(wù)(1ms對(duì)于CPU來說是很長的了),所以會(huì)返回調(diào)用方,然后打印相同的時(shí)間,一秒鐘之后會(huì)打印執(zhí)行完畢。

C#中怎么使用Task.Yeild()函數(shù)

      Test3()調(diào)用了Task.Yeild()函數(shù),主動(dòng)讓出執(zhí)行權(quán),所以會(huì)直接返回調(diào)用方,然后打印相同的時(shí)間,一秒之后會(huì)打印執(zhí)行完畢。

C#中怎么使用Task.Yeild()函數(shù)

      可以看到,開頭的結(jié)論是正確的。那么,有什么意義呢?Yeild的意思在這里其實(shí)就是退讓,讓出的意思,讓出什么呢?就是讓出執(zhí)行權(quán),這與Thread.sleep(0)讓出CPU執(zhí)行權(quán)給其他線程(前提是有其他線程競爭)有機(jī)會(huì)執(zhí)行是一個(gè)道理。

      請(qǐng)看我的例子:

public static async Task OP1()
{
   while (true)
   {
     await Task.Yield();//這里會(huì)捕捉同步上下文,由于是控制臺(tái)程序,沒有同步上下文,所以默認(rèn)的線程池任務(wù)調(diào)度器變成同步上下文
                   //也就是說后面的代碼將會(huì)在線程池上執(zhí)行,由于線程池工作線程數(shù)量設(shè)置為1,所以必須主動(dòng)讓出執(zhí)行權(quán),讓其他的
                   //任務(wù)有執(zhí)行的機(jī)會(huì)
     Console.WriteLine("OP1在執(zhí)行");
     Thread.Sleep(1000);//模擬一些需要占用CPU的操作
   }
}
public static async Task OP2()
{
   while (true)
   {
     await Task.Yield();
     Console.WriteLine("OP2在執(zhí)行");
     Thread.Sleep(1000);
   }
}
static async Task Main(string[] args)
{
   ThreadPool.SetMinThreads(1, 1);
   ThreadPool.SetMaxThreads(1, 1);
   //Task.Run()方法默認(rèn)使用線程池任務(wù)調(diào)度器執(zhí)行任務(wù),由于主線程不是線程池線程,所以使用Task.Run()
   var t = Task.Run(async () =>
   {
     var t1 = OP1();
     var t2 = OP2();
     await Task.WhenAll(t1, t2);
   });
   await t;
   Console.ReadLine();
}

C#中怎么使用Task.Yeild()函數(shù)

      可以看出OP1()和OP2()兩個(gè)協(xié)程(Task)互相爭用一個(gè)線程(用戶模式下的CPU),如果不主動(dòng)讓出執(zhí)行權(quán),另一個(gè)協(xié)程(Task)將不會(huì)有機(jī)會(huì)執(zhí)行。

      例如:

public static async Task OP2()
{
   while (true)
   {
     await Task.CompletedTask;//或者是直接去掉
     Console.WriteLine($"OP2在執(zhí)行 {DateTime.Now}");
     Thread.Sleep(1000);
   }
}

      這樣OP1()將永遠(yuǎn)不會(huì)有機(jī)會(huì)執(zhí)行。

C#中怎么使用Task.Yeild()函數(shù)

看完上述內(nèi)容,有沒有對(duì)C#中怎么使用Task.Yeild()函數(shù)有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI