繁体   English   中英

如果我以昂贵的方法返回Task,是否应该添加async修饰符?

[英]Should I add the async modifier if I return a Task in an expensive method?

如果我们有一个具有async修饰符但不使用await运算符的方法,则C#编译器已经警告我们。

根据这个答案,没有必要在异步方法的末尾添加一个await (在这种情况下,只需删除async修饰符即可)。

但是,如果该方法需要执行昂贵的同步操作,然后再调用后续的真正异步方法,该怎么办?

例如,如果我使用HttpClient

private readonly HttpClient client = ...

public Task<HttpResponseMessage> CallMyWebServiceMethod() {

    HttpRequestMessage request = this.SomeExpensiveButSynchronousMethod();

    return this.client.SendAsync( request );
}

此代码将阻止调用方(由于SomeExpensiveButSynchronousMethod )。

但是,如果我将代码更改为此:

public async Task<HttpResponseMessage> CallMyWebServiceMethod() {

    HttpRequestMessage request = this.SomeExpensiveButSynchronousMethod();

    return await this.client.SendAsync( request );
}

我这样称呼它:

HttpResponse response = await myWrapper.CallMyWebServiceMethod();

...我知道TPL会立即启动后台线程,然后在后台线程中运行CallMyWebServiceMethod ,恢复父代码想要的任何内容,使整个调用在该过程中成为非阻塞状态,然后在Task完成并返回HttpResponse

...如果是这种情况,那似乎是矛盾的。

如果我错了,并且调用一直阻塞,直到到达SendAsync那么如何在与HttpClient用于其请求的同一后台线程上执行SomeExpensiveButSynchronousMethod

根据这个答案,没有必要在异步方法的末尾添加一个await(在这种情况下,只需删除async修饰符即可)。

这太简单了。 参见我关于消除异步和等待的博客文章。

但是,如果该方法需要执行昂贵的同步操作,然后再调用后续的真正异步方法,该怎么办?

这种情况很少见,但是IMO的适当解决方案是同步执行同步操作(即,不包装在Task.Run ),并确保记录其行为

我知道TPL会立即启动后台线程,然后在后台线程中运行CallMyWebServiceMethod,恢复父代码想要的任何内容,使整个调用在该过程中成为非阻塞状态,然后在Task完成并返回HttpResponse之后继续执行。

那根本不会发生什么。 您可能会发现我的async介绍很有帮助。 引用:

异步方法的开始与其他方法一样执行。 也就是说,它会同步运行,直到达到“ await”(或引发异常)为止。

实际上,您的两个示例在执行SomeExpensiveButSynchronousMethod 同步阻塞了调用者。

如果我错了,并且调用一直阻塞,直到到达SendAsync,那么如何在与HttpClient用于其请求的同一后台线程上执行SomeExpensiveButSynchronousMethod?

HttpClient的请求不使用后台线程,因此问题的这一部分没有意义。 有关异步I / O如何工作的更多信息,请参见我的博客文章There No Thread

要回答实际问题:

如果我以昂贵的方法返回Task,是否应该添加async修饰符?

是。 但是,您这样做的原因不是“使其异步”; 这样一来,将捕获SomeExpensiveButSynchronousMethod中的所有异常并将其放置在返回的Task ,这是遵循基于任务的异步模式(TAP)的方法的预期语义。

我知道TPL会立即启动后台线程,然后运行CallMyWebServiceMethod

不,那不会发生。 async方法的第一个同步部分是async执行的。 如果要确保它不会阻塞当前线程,则应使用Task.Run()

您昂贵的方法将以两种方式阻止调用者。 async不会神奇地为您创建线程,这就是Task所做的(有时)。 因此,如果添加async并等待SendAsync ,则只会不必要地增加状态机的开销。

另请参阅http://blog.stephencleary.com/2016/12/eliding-async-await.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM