繁体   English   中英

await Task.CompletedTask 是否意味着异步方法将同步运行?

[英]Does await Task.CompletedTask mean the async method will run synchronously?

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将始终实际同步执行该方法?

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

您可以在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

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

private const int TASK_STATE_COMPLETED_MASK = TASK_STATE_CANCELED | TASK_STATE_FAULTED 
                                              | TASK_STATE_RAN_TO_COMPLETION;

根据@Marc 的回答,等待一个已经IsCompleted任务短路等待器和执行将在同一线程上同步继续。

根据我的评论,直接await Task.CompletedTaskTask.FromResult创建的 Task 是非常不寻常的,因为这个编译器会生成一个不必要的异步状态机 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()在注入的(现在被GetDateAsync()ISomeInterface ,并且通常不会更明智的是被调用的方法只是在任务上盖上橡皮图章并同步返回假数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM