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

时间:2014-11-18 11:33:04

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

如果我总是使用以下模式,我开始想知道异步编程:

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();
}

2 个答案:

答案 0 :(得分:2)

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

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;
}

请参阅Yuval Itzchakov的另一个选择。 关键是,在这里你开始两个,然后等待他们。在你的例子中你开始一个,等待它完成,然后开始下一个......等等。

答案 1 :(得分:1)

这取决于你想要做什么。 通常,当您只在方法内部进行一次异步调用时,您可以节省自己的状态机开销,只需返回Task,这将等待调用堆栈的更高位置。

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

同时运行这两个操作
public async Task<int> SomeOtherMethodAsync()
{
    int[] results = await Task.WhenAll(LongRunningThirdMethod(), LongRunningForthMethod());
    return results.Sum();
}

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