【问题标题】:Does await Task.CompletedTask mean the async method will run synchronously?await Task.CompletedTask 是否意味着异步方法将同步运行?
【发布时间】:2020-05-03 07:04:55
【问题描述】:
static async Task WaitTaskCompleted()
{
    //Use Thread A before await Task.CompletedTask
    await Task.CompletedTask;
    //Will the code after await Task.CompletedTask always use Thread A, or there is chance to have a Thread B?
}

这意味着await Task.CompletedTask 将始终同步执行该方法?

【问题讨论】:

  • Related: stackoverflow.com/q/30493036 在这种情况下方法不需要异步,也不需要等待完成的任务。
  • 同意;回应@StuartLC 的观点:这可能只是/* stuff here */ return Task.CompletedTask; 没有async 修饰符

标签: c# async-await task


【解决方案1】:

是的,这段代码将始终同步运行;仅当遇到第一个 incomplete awaitable 时才会调用主延续编译器 goo。

您可以在sharplab 中看到这一点 - 尤其是在这里:

awaiter = Task.CompletedTask.GetAwaiter();
if (!awaiter.IsCompleted)
{
    num = (<>1__state = 0);
    <>u__1 = awaiter;
    <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
    return;
}

实现异步的是AwaitUnsafeOnCompleted(...) + return

【讨论】:

    【解决方案2】:

    只是为了其他读者的理智,Task.FromResult&lt;T&gt;Task.CompletedTaskTask.FromCancelationTask.FromException() 的通常目的是为各种类型的Task 提供简单的工厂方法(即有/没有返回有效负载,或返回异常或模拟取消),并且在所有情况下,返回的任务将被视为IsCompleted,根据the source:

    private const int TASK_STATE_COMPLETED_MASK = TASK_STATE_CANCELED | TASK_STATE_FAULTED 
                                                  | TASK_STATE_RAN_TO_COMPLETION;
    

    根据@Marc 的回答,等待已经IsCompleted 的任务会使等待程序短路,并且执行将在同一线程上同步继续。

    根据我的评论,直接 awaitTask.CompletedTaskTask.FromResult 创建的任务是非常不寻常的,因为此编译器会生成不必要的 async state machine wrapper,这在 OP 的场景中完全是矫枉过正。

    使用各种已完成的 Task 工厂方法的常见场景是在单元测试期间进行模拟,其中被模拟的类/接口需要返回 Task,否则不需要 async。例如,如果以下生产接口需要模拟或存根:

    public interface ISomeInterface
    {
         Task<DateTime> GetDateAsync();
    }
    

    可以按如下方式存根:

    public class MyMock : ISomeInterface
    {
        public Task<DateTime> GetDateAsync() // no async
        {
            // Directly return a completed task return a fake result
            return Task.FromResult(new DateTime(2019, 11, 12, 0, 0, 0, DateTimeKind.Utc));
        }
    }
    

    被测试的生产类(SUT)可能会等待GetDateAsync() 在注入(现在被模拟)ISomeInterface 上的结果,并且通常不会比被调用的方法只是 橡胶盖章更明智 Task 并同步返回假数据。

    【讨论】:

      猜你喜欢
      • 2013-04-11
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-07
      • 2012-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多