【问题标题】:await Task.CompletedTask vs return等待 Task.CompletedTask 与返回
【发布时间】:2021-01-01 06:11:28
【问题描述】:

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

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

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

这个?

public async Task Test()
{
    return;
}

据我了解,两者的status 都将设置为TaskStatus.RanToCompletion,尽管根据Task.FromResult 的解释,我觉得这可能与物理时间或类似的东西有关:

该方法通常用于任务的返回值立即知道而无需执行更长的代码路径的情况。

如果我研究了 GitHub 上的 MS 代码、MS Docs 以及我能找到的每个链接,我将不胜感激,但它在任何地方都没有给出明确的解释。我还在较大的方法末尾看到await Task.CompletedTask,根据我从MS on GitHub 找到的一些cmets 实际上是错误的,因为它不应该包含它,他们希望将其从repo 中清除。

如果还对Task.FromResult(因为他们是兄弟姐妹)进行了明确的揭秘,那将不胜感激,因为我还不清楚何时使用:

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

在此:

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

【问题讨论】:

  • 通常,Task.CompletedTaskTask.FromResult(...) 会返回,而不是等待。这些允许您实现一个返回 Task/Task&lt;T&gt; 而没有 async 机制的方法。
  • 谢谢,这绝对有帮助。那么当你使用 async/await 时,你只需要返回/返回值而不是 Task?

标签: c# async-await task-parallel-library


【解决方案1】:

让我们从消费者的角度来看问题。

如果您定义一个接口,该接口强制执行返回 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;
    }
}

此异步方法缺少“等待”运算符,将同步运行。考虑使用 'await' 运算符来等待非阻塞 API 调用,或使用 'await Task.Run(...)' 在后台线程上执行 CPU 密集型工作。

换句话说,这个实现没有定义状态机。一个异步方法根据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,如果它同步完成,那么我们不需要在堆上分配它们来延长它的生命超出方法的范围。

有关更多信息,请阅读以下文章:

【讨论】:

    猜你喜欢
    • 2017-10-21
    • 1970-01-01
    • 2013-02-18
    • 2014-06-30
    • 2020-03-13
    • 1970-01-01
    • 1970-01-01
    • 2014-10-06
    • 2021-04-30
    相关资源
    最近更新 更多