在直接从调用另一个库返回任务的库中使用ConfigureAwait(false)是否有利?

Tod*_*ier 8 .net c# task-parallel-library async-await dotnet-httpclient

这个问题的后续行动.我有一个包含许多异步方法的库,可以进行精简包装HttpClient.实际上他们只是做了一些设置并直接Task返回从HttpClient通话中返回的内容:

public Task DoThingAsyc() {
    // do some setup
    return httpClient.DoThingAsync();
}
Run Code Online (Sandbox Code Playgroud)

我在考虑是否要添加ConfigureAwait(false)这些调用.流行的智慧似乎是"是的,总是在图书馆那样做".但是在这种情况下,它会引入一些(可能是可忽略的)开销,因为ConfigureAwait返回一个ConfiguredTaskAwaitable需要被包回到a Task中以便不改变方法签名.当然不难编码:

public async Task DoThingAsyc() {
    // do some setup
    return await httpClient.DoThingAsync().ConfigureAwait(false);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,效率优势是否ConfigureAwait(false)会超过这种情况下引入的额外开销?以上哪个例子被认为是更好的做法?

Luc*_*ski 11

不,不要这样做.

由于你没有使用await,你不应该提前配置它.您的图书馆的来电者有责任ConfigureAwait拨打电话.调用者可能想要打电话ConfigureAwait(true)而不是ConfigureAwait(false)- 你不知道.

调用ConfigureAwait(false)库的代码只有当最佳实践在图书馆上等待.

大多数情况下,代码如下:

async Task<Something> DoSomethingAsync()
{
    return await DoSomethingElseAsync().ConfigureAwait(false);
}
Run Code Online (Sandbox Code Playgroud)

相当于:

Task<Something> DoSomethingAsync()
{
    return DoSomethingElseAsync();
}
Run Code Online (Sandbox Code Playgroud)

如果 DoSomethingElseAsync尊重Task合同(例如,如果它返回失败Task而不是抛出异常).

为此创建一个额外的状态机只是添加一层没有附加值的包装代码 - 最好直接返回Task.

换句话说:你这样做没有任何效率上的好处,恰恰相反.


i3a*_*non 7

不,ConfigureAwait顾名思义,配置await.如果您不需要,await则无需进行配置.

添加async-await只是为了使用ConfigureAwait它没有附加值,因为它只影响你的方法而不影响调用方法.如果呼叫者需要使用,ConfigureAwait他们将自己这样做.

由于Task许多原因(例如异常处理),具有异步方法而不是简单返回方法是有效选择,并且它将需要使用ConfigureAwaitConfigureAwait不是单独执行此操作的充分理由.

  • 有趣的是,我一直在思考这个问题但是直到你们指出它才发生在我身上 - "没有'等待',所以你到底在配置什么?" 一双新鲜眼睛的好处! (6认同)