异步设计模式 - 哪一个更好

本文关键字:更好 哪一个 设计模式 异步 | 更新日期: 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();
}

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