从异步方法返回

时间:2017-08-14 13:44:01

标签: c# asynchronous async-await

我有一个返回任务的异步方法。在下列情况下我是否需要退货?

    public async Task UpdateProductSpecificationsAsync()
    {
        await _productRepository.UpdateProductSpecificationsAsync(); //Takes long time to execute
    }

以下代码示例是否彼此等效?

    public Task UpdateProductSpecifications()
    {
        _productRepository.UpdateProductSpecifications(); //Takes long time to execute
        return Task.FromResult(0);
    }

    public Task UpdateProductSpecifications()
    {
        _productRepository.UpdateProductSpecifications(); //Takes long time to execute
        return Task.CompletedTask;
    }

我是否应该等待Task.TaskCompleted

1 个答案:

答案 0 :(得分:3)

  

我有一个返回任务的异步方法。在下列情况下我是否需要退货?

async Task方法相当于非异步void方法。与非异步void方法一样,async Task方法无法返回任何内容。

那就是说,你的例子似乎很奇怪。如果你要在方法中做的就是等待其他一些异步方法,那么你根本不应该使用async / await。只需直接返回Task

public Task UpdateProductSpecificationsAsync()
{
    return _productRepository.UpdateProductSpecificationsAsync();
}
  

以下代码示例是否彼此等效?

定义“等效”。对我来说,他们绝对不是不等同于。第一个创建一个新的Task<int>对象,并将该对象作为Task返回。调用代码必须将其强制转换回Task<int>以查看结果值。

第二个返回静态Task.CompletedTask属性值,它是一个单例对象,每个进程只分配一次。调用者无法读取结果值。

调用者必须进行额外的工作才能直接观察这些差异,但至少,返回对单例对象的引用比每次创建新对象更有效。当然,这是否重要取决于您调用该方法的频率。

所有这一切,我不明白为什么在这种情况下,你不会像这样实现它(假设没有_productRepository方法的真正异步版本):

public Task UpdateProductSpecificationsAsync()
{
    return Task.Run(() => _productRepository.UpdateProductSpecifications());
}

然后你会得到实际的异步行为,这是调用者通常所期望的。您的版本会强制调用者等待查找的方法,就像它是异步的一样。恕我直言,写一个谎言代码是一个非常糟糕的主意。

  

我是否应该等待Task.TaskCompleted [原文如此]?

你的意思是直接?或者通过代码不知道它已被提交Task.CompletedTask引用?我会假设前者,因为期望后者知道它正在做什么是不合理的。

这对我来说似乎是一个过于宽泛的问题。 任何情况?这是可以解释的。

那就是说,我会对这个问题说“不”。等待你知道的事情的重点是什么? await不会回复给调用者,因为等待已经完成。这对我来说似乎是一种浪费。

我可以想象一个等待Task.CompletedTask的场景,以达到一些其他所需的副作用。我见过比生产代码更奇怪的东西。但我不会推荐它。无论我们谈论什么假设的副作用,我都相信这不是一个记录在案的副作用,所以人们会依赖未来可能发生变化的无证实施细节。

不要写脆弱的代码。编写仅依赖于记录的行为的代码,并且只做有明显意义的事情。 (以及必然结果:如果你打破这个规则,至少要写一个非常详细的评论来解释你为什么编写奇怪的,脆弱的代码。)