等待 Task.CompletedTask 与 return

await Task.CompletedTask vs return

我试图理解 await Task.CompletedTaskreturn 之间的区别,但似乎找不到任何明确定义的解释。

为什么/什么时候使用这个:

public async Task Test()
{
    await Task.CompletedTask;
}

超过这个?

public async Task Test()
{
    return;
}

据我了解,两者都会将 status 设置为 TaskStatus.RanToCompletion,但根据 [=23] 的解释,我感觉这可能与物理时间或类似的东西有关=]:

The method is commonly used when the return value of a task is immediately known without executing a longer code path.

我会在 GitHub、MS 文档以及我能找到的每个 link 上研究过 MS 代码,但没有任何地方给出明确的解释,因此我希望能够清楚地揭开这一点的神秘面纱。我还在较大方法的末尾看到 await Task.CompletedTask,根据我从 MS on GitHub 中发现的一些评论,这些方法实际上是错误的,因为它不应该包含它,他们希望将它从回购中清除。

如果也清楚地揭开 Task.FromResult 的神秘面纱(因为他们是兄弟姐妹),那将不胜感激,因为我还不清楚何时使用:

public async Task<bool> Test()
{
    return await Task.FromResult(true);
}

关于这个:

public async Task<bool> Test()
{
    return true;
}

我们来看consumer-side的问题。

如果你定义了一个接口,它强加了一个 returns 一个 Task 的操作,那么你不会说任何关于它将如何计算/执行的信息(所以,没有 async 方法签名中的访问修饰符)。这是一个实施细节

界面

public interface ITest
{
    Task Test();
    Task<bool> IsTest();
}

因此,如何实现接口取决于您。

您可以以同步方式执行此操作,因为没有 async 关键字而不会生成任何 AsyncStateMachine

实施 #1

public class TestImpl : ITest
{
    public Task Test()
    {
        return Task.CompletedTask;
    }

    public Task<bool> IsTest()
    {
        return Task.FromResult(true);
    }
}

或者您可以尝试以异步方式实现它,但不使用 await 运算符。在这里您将收到 CS1998 警告。

实施#2

public class TestImpl : ITest
{
    public async Task Test()
    {
        return;
    }

    public async Task<bool> IsTest()
    {
        return true;
    }
}

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

换句话说,这个实现没有定义状态机。一个async方法根据await个关键字分为不同的状态:

  • before_the_await_1,
  • after_the_await_1_but_before_the_await_2
  • after_the_await_2_but_before_the_await_3
  • ...

如果您没有任何等待,那么您将拥有一个状态,该状态将 运行 同步(无需保留状态、执行异步操作然后调用 MoveNext() ).


或者您可以尝试使用 await 运算符以异步方式实现它。

实施 #3

public class TestImpl : ITest
{
    public async Task Test()
    {
        await Task.CompletedTask;
    }

    public async Task<bool> IsTest()
    {
        return await Task.FromResult(true);
    }
}

在这种情况下会有一个异步状态机,但它不会分配到堆上。默认情况下,它是一个 struct,如果它同步完成,那么我们不需要在堆上分配它们来延长它在方法范围之外的寿命。

有关更多信息,请阅读这些文章: