C#关于Task.Yeild()函数的讨论

这篇文章主要介绍了C#中关于Task.Yeild()函数的相关资料,文中讲解非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下

      在与同事讨论async/await内部实现的时候,突然想到Task.Yeild()这个函数,为什么呢,了解一点C#async/await内部机制的都知道,在await一个异步任务(函数)的时候,它会先判断该Task是否已经完成,如果已经完成,则继续执行下去,不会返回到调用方,原因是尽量避免线程切换,因为await后面部分的代码很可能是另一个不同的线程执行,而Task.Yeild()则可以强制回到调用方,或者说主动让出执行权,给其他Task执行的机会,可以把Task理解为协程,Task.Yeild()和Thread.sleep(0)有点相同。

      为了证明我的结论成立,请看代码:


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

      按照开头的理论,Test1()异步函数由于await了一个已经完成的任务,所以会继续往下执行,阻塞1秒钟,然后回到调用方,打印的时间之差会相隔一秒。


public static async Task OP1()
{
   while (true)
   {
     await Task.Yield();//这里会捕捉同步上下文,由于是控制台程序,没有同步上下文,所以默认的线程池任务调度器变成同步上下文
                   //也就是说后面的代码将会在线程池上执行,由于线程池工作线程数量设置为1,所以必须主动让出执行权,让其他的
                   //任务有执行的机会
     Console.WriteLine("OP1在执行");
     Thread.Sleep(1000);//模拟一些需要占用CPU的操作
   }
}
public static async Task OP2()
{
   while (true)
   {
     await Task.Yield();
     Console.WriteLine("OP2在执行");
     Thread.Sleep(1000);
   }
}
static async Task Main(string[] args)
{
   ThreadPool.SetMinThreads(1, 1);
   ThreadPool.SetMaxThreads(1, 1);
   //Task.Run()方法默认使用线程池任务调度器执行任务,由于主线程不是线程池线程,所以使用Task.Run()
   var t = Task.Run(async () =>
   {
     var t1 = OP1();
     var t2 = OP2();
     await Task.WhenAll(t1, t2);
   });
   await t;
   Console.ReadLine();
}


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

      这样OP1()将永远不会有机会执行。

以上就是C#中关于Task.Yeild()函数的讨论的详细内容,更多关于C# Task.Yeild()的资料请关注得得之家其它相关文章!

本文标题为:C#关于Task.Yeild()函数的讨论