簡體   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