【问题标题】:Async design pattern - which one is better? [closed]异步设计模式——哪一种更好? [关闭]
【发布时间】:2014-11-18 20:14:33
【问题描述】:

我开始想知道我是否应该始终使用以下模式进行异步编程:

public async Task<int> MyMethodAsync()
{
    return await SomeOtherMethodAsync();
}

或者是否安全且不会产生任何缺点,将此代码简化为:

public Task<int> MyMethodAsync()
{
    return SomeOtherMethodAsync();
}

我已经开始通过互联网阅读,但找不到任何答案,所有异步编程都只提到了第一种模式。

更新 1

根据一些答案,在琐碎的方法中,第二个是正确的。但是如果我以以下方式扩展和编写方法 - 这仍然与上面的代码有关,只是为了显示 SomeOtherMethodAsync 方法内部的内容:

public async Task<int> SomeOtherMethodAsync()
{
    var result1 = await LongRunningThirdMethod();
    var result2 = await LongRunningForthMethod();

    return result1 + result2;
}

并将我的第二个示例修改为:

public Task<int> MyMethodAsync()
{
    SomeSyncMethod();
    SomeOtherSyncCode();

    return SomeOtherMethodAsync();
}

【问题讨论】:

  • 顺便说一句,SomeOtherMethodAsync 在启动 LongRunningFourthMethod 之前不必要地等待 LongRunningThirdMethod - 实例化两个任务并然后等待它们,以便它们可以同时运行。
  • 谢谢,这只是一个简单的例子,里面是什么,以扩展主要问题。

标签: c# asynchronous async-await .net-4.5


【解决方案1】:

在这种特定情况下,不需要等待开销。

async/await 是为了让之前的回调地狱,感觉更像是同步编程。 而且由于在 Async 调用之后你没有任何事情要做,所以在这种情况下确实不需要使用 await。

所以你只返回 async 方法是对的,它甚至仍然保持它的承诺。

更新 1

这两种情况都是正确的。当您执行 await/async 时,编译器会在后台创建一个状态机来为您处理所有回调,如果您不使用它,则无需创建一个。所以这两个例子都是正确的 async/await 代码。

您可以通过同时等待两个任务来优化它。

public async Task<int> SomeOtherMethodAsync()
{
    var resultTask1 = LongRunningThirdMethod();
    var resultTask2 = LongRunningForthMethod();

    await Task.WhenAll(resultTask1, resultTask2);

    return resultTask1.Result + resultTask2.Result;
}

甚至:

public async Task<int> SomeOtherMethodAsync()
{
    var resultTask1 = LongRunningThirdMethod();
    var resultTask2 = LongRunningForthMethod();

    return await resultTask1 + await resultTask2;
}

请参阅 Yuval Itzchakov 答案以获取另一种选择。 关键是,在这里你开始两个,然后等待它们。在您的示例中,您开始一个,等待它完成,然后开始下一个......等等。

【讨论】:

  • 值得注意的是,这仅适用于所讨论的微不足道的情况 - 如果这应该代表一个一般示例,那么它可能并不那么简单。
  • @AntP 正确,我同意。但是如果我们看一个方法,只调用一个异步方法,之后不需要调用使用异步调用返回的东西,你可以把“句柄”返回给调用者,让它处理它。
【解决方案2】:

这取决于你想要做什么。 通常,当您只在方法中进行一次异步调用时,您可以节省状态机开销并简单地返回 Task,这将在调用堆栈的更高层等待。

您的第二个示例(更新 1)必须等待异步操作的两个结果返回。你可以做的是修改你的代码,让这两个操作使用Task.WhenAll同时运行:

public async Task<int> SomeOtherMethodAsync()
{
    int[] results = await Task.WhenAll(LongRunningThirdMethod(), LongRunningForthMethod());
    return results.Sum();
}

这样,您不必按顺序等待每个操作完成。一旦它们都返回,您就可以计算总和。

【讨论】:

  • 并发示例是微妙而精巧的。喜欢使用Sum()
  • 谢谢,我同意 update1 SomeOtherMethodAsync 方法可以写得更好,作为你的例子。但实际上它只是扩展该方法内部的内容。是改变理解和实现模式1 vs 模式2
  • await 在模式 1 中是无法避免的,因为您有两个异步操作需要完成,因为返回值取决于它们。在模式 2 中,您可以向上传播 Task,并留给调用者使用 await 处理它。
猜你喜欢
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
  • 2010-12-02
  • 1970-01-01
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多