C#关于在返回值为Task方法中使用Thread.Sleep引发的思考

起因

最近有个小伙伴提出了一个问题,就是在使用.net core的BackgroundService的时候,对应的ExecuteAsync方法里面写如下代码,会使程序一直卡在当前方法,不会继续执行,代码如下:

public class BGService : BackgroundService
{
   
    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
   
        while (true)
        {
   
            Thread.Sleep(1000);
        }
    }
}

其实这个问题我们还是对Task和异步执行过程理解不够深入导致的,所以本篇文章笔者就以这个问题来对Task和异步方法执行过程来做源码的探究。
PS:本文只贴出重要的代码和注释,不是其全部的代码,读者多关注下注释。

解析

Thread.Sleep和Task.Delay的区别

  • Thread.Sleep分析
    它会挂起当前执行线程指定时间(调用了系统内核的方法),而这时候当前线程是不能做任何其他的事情,只能等待指定时间后再执行。最终执行的代码如下图:
private static void SleepInternal(int millisecondsTimeout)
{
   
    //这是Windows平台,不同平台调用的方法不一样
    Interop.Kernel32.Sleep((uint)millisecondsTimeout);
}
  • Task.Delay分析
    它的执行实际上是交给了TimerQueueTimer,也就是定时器队列(每个进程里,所有的timer执行都在一个TimerQueueTimer队列集合里面),在指定时间后回调方法,由ThreadPool中的线程执行。实际执行代码如下图:
public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
{
   
    if (millisecondsDelay < -1)
    {
   
        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.millisecondsDelay, ExceptionResource.Task_Delay_InvalidMillisecondsDelay);
    }
    //开始执行Delay方法
    return Delay((uint)millisecondsDelay, cancellationToken);
}

private static Task Delay(uint millisecondsDelay, CancellationToken cancellationToken) =>
    cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) :
    millisecondsDelay == 0 ? CompletedTask :
                                          //它继承自DelayPromise,只不过加了CancellationToken
    cancellationToken.CanBeCanceled ? new DelayPromiseWithCancellation(millisecondsDelay, cancellationToken) :
    //最终执行这个
    new DelayPromise(millisecondsDelay);

internal DelayPromise(uint millisecondsDelay)
{
   
    if (millisecondsDelay != Timeout.UnsignedInfinite)
    {
   
    

你可能感兴趣的:(c#,.netcore)