18

Delay(0)总是内联吗?根据我的经验,它确实:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication
{
    class Program
    {
        static async Task Test()
        {
            await Task.Yield();
            Console.WriteLine("after Yield(), thread: {0}", Thread.CurrentThread.ManagedThreadId);
            await Task.Delay(0);
            Console.WriteLine("after Delay(0), thread: {0}", Thread.CurrentThread.ManagedThreadId);
            await Task.Delay(100);
            Console.WriteLine("after Delay(100), thread: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        static void Main(string[] args)
        {
            Console.WriteLine("Main thread: {0}", Thread.CurrentThread.ManagedThreadId);
            Test().Wait();
        }
    }
}

这是一个控制台应用程序,因此线程池用于继续。输出:

Main thread: 11
after Yield(), thread: 7
after Delay(0), thread: 7
after Delay(100), thread: 6
4

2 回答 2

26

在内部Task.Delay,它看起来像这样(单参数(int)版本只是调用以下版本):

[__DynamicallyInvokable]
public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
{
    if (millisecondsDelay < -1)
    {
        throw new ArgumentOutOfRangeException("millisecondsDelay", Environment.GetResourceString("Task_Delay_InvalidMillisecondsDelay"));
    }
    if (cancellationToken.IsCancellationRequested)
    {
        return FromCancellation(cancellationToken);
    }
    if (millisecondsDelay == 0)
    {
        return CompletedTask;
    }
    DelayPromise state = new DelayPromise(cancellationToken);
    if (cancellationToken.CanBeCanceled)
    {
        state.Registration = cancellationToken.InternalRegisterWithoutEC(delegate (object state) {
            ((DelayPromise) state).Complete();
        }, state);
    }
    if (millisecondsDelay != -1)
    {
        state.Timer = new Timer(delegate (object state) {
            ((DelayPromise) state).Complete();
        }, state, millisecondsDelay, -1);
        state.Timer.KeepRootedWhileScheduled();
    }
    return state;
}

如您所见:

    if (millisecondsDelay == 0)
    {
        return CompletedTask;
    }

这意味着它始终返回一个已完成的任务,因此您的代码将始终在该特定await行之后继续运行。

于 2013-08-30T07:24:34.447 回答
11

是的,它确实。检查反射器中的 IL 显示(以及其他逻辑):

if (millisecondsDelay == 0)
{
    return CompletedTask;
}

所以是的,在这种情况下,它会将你已经完成的任务交还给你。

请注意,await包括检查的实现确保已完成的任务不会导致额外的上下文切换,所以是的:您的代码将继续运行而不会在这里暂停呼吸。

当答案已知/同步可用时,建议返回已完成的任务;Task为常见的结果值缓存 s 也是很常见的。

于 2013-08-30T07:24:43.297 回答