异步设计模式 - 哪一个更好
本文关键字:更好 哪一个 设计模式 异步 | 更新日期: 2023-09-27 18:30:53
我开始想知道异步编程是否应该始终使用以下模式:
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();
}
在这种特定情况下,不需要等待开销。
async/await 旨在使之前的回调地狱,感觉更像是同步编程。而且由于在异步调用后您无事可做,因此在这种情况下实际上无需使用 await。
因此,您只返回异步方法是对的,它甚至仍然保持其承诺。
更新 1
这两种情况都是正确的。当您执行 await/async 时,编译器会在后台创建一个状态机来为您处理所有回调,如果您不使用它,则无需创建一个状态机。所以这两个例子都是正确的异步/等待代码。
不过,您可以通过同时等待两个任务来优化它。
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;
}
参见尤瓦尔·伊茨恰科夫的答案,了解另一种选择。关键是,在这里你开始两者,然后等待它们。在您的示例中,您开始一个,等待它完成,然后启动下一个...等。
这取决于您要做什么。通常,当您只在方法中进行一次异步调用时,您可以节省状态机开销并简单地返回Task
,这将在调用堆栈的更高位置等待。
您的第二个示例(更新 1)必须等待异步操作的两个结果返回。您可以做的是修改代码,以便使用Task.WhenAll
同时运行两个操作:
public async Task<int> SomeOtherMethodAsync()
{
int[] results = await Task.WhenAll(LongRunningThirdMethod(), LongRunningForthMethod());
return results.Sum();
}
这样,您就不会按顺序等待每个操作完成。一旦它们都返回,您就会计算总和。