[英]If i add async keyword to a method which which should return a Task it wrap the return value in Task?
[英]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.