任务延迟是否创建新线程?

Does Task delay create new Thread?

请问下面的Task.Delay调用Task.Run是线程id改变的原因还是背后的逻辑不同?

async Task Main()
{
     Console.WriteLine(Thread.CurrentThread.ManagedThreadId); //11
     await Task.Delay(200);
     Console.WriteLine(Thread.CurrentThread.ManagedThreadId); //22
}

不,Task.Delay 不调用下面的 Task.Run。它只是 returns 一个 Task 在指定的持续时间后完成,并在内部调用任何 continuations that are attached to it on the ThreadPool. It uses a System.Threading.Timer。它的实现如下所示:

public class Task
{
    public static Task Delay(int millisecondsDelay)
    {
        var tcs = new TaskCompletionSource();
        _ = new Timer(_ => tcs.SetResult(), null, millisecondsDelay, -1);
        return tcs.Task;
    }
}

因此,当您 await Task.Delay 时,await 之后的延续运行在调用 Timer 回调的同一线程上¹,这恰好是一个ThreadPool 个线程。

注:以上实现只是一个例子。这不是实际的实现,也不能保证能正常工作。 Timer 实例未存储在任何地方,因此它可能会在调用回调之前被垃圾收集,从而导致 never-completing Task.

¹ 假设没有 SynchronizationContext