用await编写异步方法?

时间:2018-06-23 13:18:30

标签: c# .net asynchronous async-await

在将方法调用传递给另一个异步方法时,调用方方法是否也应该异步并使用await,还是我应该简单地传递它从被调用方收到的Task?如果调用方法进行了更多的准备,该怎么办?

public Task<Message> Unsubscribe(int subscriptionId, CancellationToken cancellationToken)
{
    var data = new MessageData
    {
        ["subscriptionId"] = subscriptionId
    };
    return SendAsync(OpCode.Unsubscribe, data, cancellationToken);
}

public Task<Message> Unsubscribe(int subscriptionId) =>
    Unsubscribe(subscriptionId, CancellationToken.None);

SendAsync是异步的,并返回Task<Message>。因此,Unsubscribe的第一个重载应该像上面这样或那样:

public async Task<Message> Unsubscribe(int subscriptionId, CancellationToken cancellationToken)
{
    var data = new MessageData
    {
        ["subscriptionId"] = subscriptionId
    };
    return await SendAsync(OpCode.Unsubscribe, data, cancellationToken);
}

另一种选择是使用Unsubscribe的第二个重载。可能像上面这样:

public async Task<Message> Unsubscribe(int subscriptionId) =>
    await Unsubscribe(subscriptionId, CancellationToken.None);

我猜想更多的异步和等待会增加编译器引入的复杂性(我在堆栈跟踪中看到了它!),并且可能会降低性能和内存消耗。但是至少它应该提供一致的异常传播。

1 个答案:

答案 0 :(得分:2)

在您引用的示例中,只返回任务而无需await很好(并且可以说是更好的选择),但这确实需要格外小心。

一旦遇到麻烦,就是在Task块中处理using时。这些行为可能有很大不同:

public async Task<Something> AwaitTheTask()
{
    using (var someResource = GetAResource())
    {
        return await SomeAsyncThing(someResource);
    }
}

public Task<Something> DontAwaitTheTask()
{
    using (var someResource = GetAResource())
    {
        return SomeAsyncThing(someResource);
    }
}

在第一个示例中,using块将不会处置someResource,直到等待的Task完成。在第二个示例中,someResource将被立即处置,很可能导致需要该资源的代码出现问题。