【问题标题】:Return a Task instead of awaiting the inner method call [duplicate]返回一个任务而不是等待内部方法调用[重复]
【发布时间】:2017-03-10 10:45:52
【问题描述】:

我看到一些同事的代码,他选择不等待数据库调用而只返回任务。例如

public Task<UpdateResult> AddActivityAsync(ClaimsPrincipal principal, Activity activity)
{
    return _userManager.SaveToDatabaseAsync(principal, activity);
}

由于_userManager.SaveToDatabaseAsync 是异步的,我会以这种方式实现

public async Task<UpdateResult> AddActivityAsync(ClaimsPrincipal principal, 
                                                                      Activity activity)
{
    return await _userManager.SaveToDatabaseAsync(principal, activity);
}

这个方法的调用方法总是等待它:

await _profile.AddActivityAsync(..., ...)

不使内部方法异步并只返回任务,让调用者等待它有什么好处?我以为我们必须一直写 Async...

【问题讨论】:

    标签: c# asynchronous async-await task


    【解决方案1】:

    视情况而定。

    必须等待,例如,如果要等待的代码绑定到 using 上下文中的对象(或被手动释放):

    using (SomeDisposableType obj = ...)
    {
        await obj.SomeOperationAsync();
    }
    

    如果您没有等待就返回了任务,那么该方法可能会抱怨该对象在完成其工作之前已被释放。 (并非所有一次性物品都会抛出ObjectDisposedException,如果您在它们被丢弃后尝试对其执行某些操作,但通常假设是个好主意)。考虑相反的情况:

    using (SomeDisposableType obj = ...)
    {
        // This returns the Task that represents the async operation,
        // and because it returns, the control goes out of the using
        // scope, and therefore obj gets disposed.
        return obj.SomeOperationAsync();
    }
    

    所以在某些情况下等待是必要的。如果不是这样,我真的想不出你不能返回 Task 本身的原因。

    【讨论】:

    • 是的,我同意您在某些情况下必须等待。但是关于你不需要的情况,因为你只返回内部结果,哪个是更好的做法?
    • 非常重要的警告必须等待如果在里面使用。好几个月都没有发现这段代码……理想情况下,编译器应该阻止使用块返回的任务,希望有一天!我发现了这个问题,与我的stackoverflow.com/questions/63584024/… 有关。我认为这个答案已更新为 Balazs,因为它涵盖了这一重要点
    【解决方案2】:

    您不需要等待返回Task&lt;T&gt; 的方法,如果您在方法上有async 关键字,则代码将异步运行。您的同事已将其删除,因此故意同步运行,并让调用代码在他们愿意的情况下实现它。

    这取决于这段代码在哪一层运行。如果它很深,最好让更高的代码层选择异步执行并在那里保持控制。

    您绝对不需要“一直写异步”。 async 关键字的目的只是将方法标记为能够返回 Task&lt;T&gt; 并能够使用 await 关键字。 await 关键字调用框架来执行任务并提供异步处理。

    TL;DR:这是一个选择。

    我欢迎任何人改进或纠正我,因为我不是大师。

    【讨论】:

    • 所以如果它只是一个异步方法的包装器,没有满足来标记包装器异步只返回任务就可以了吗?如果我把它异步,每次等待时会增加开销吗?在那个简单包装的案例中,不要等待对我来说似乎更好
    • @lloyd 在我看来,那篇文章并没有说明正在发生的事情,而不是一个线程。它似乎在说的是使用了一个线程,但不一定是一个新线程。那么,await 会导致新的上下文吗?
    猜你喜欢
    • 2018-04-27
    • 1970-01-01
    • 2013-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多