将非异步方法(进行网络调用)包装成异步
Wrapping a non async-method (which does web calls) into async
我知道您应该只对非 "CPU-intensive" 的内容使用异步,例如文件写入、网络调用等,因此我也知道将每个方法包装到 Task.Run
或类似的东西中是没有意义的。
然而,当我知道一个方法执行网络调用但它不提供异步接口时我应该怎么做。在这种情况下值得包装吗?
具体例子:
我在我的 WebApi 应用程序(服务器)中使用 CSOM(客户端 SharePoint 对象模型)并想要获取 SharePoint 列表。
这通常是这样完成的:
[HttpGet]
[Route("foo/{webUrl}")]
public int GetNumberOfLists(string webUrl)
{
using (ClientContext context = new ClientContext(webUrl))
{
Web web = context.Web;
context.Load(web.Lists);
context.ExecuteQuery();
return web.Lists.Count;
}
}
然后我想把它改成这样:
[HttpGet]
[Route("foo/{webUrl}")]
public async Task<int> GetNumberOfLists(string webUrl)
{
using (ClientContext context = new ClientContext(webUrl))
{
Web web = context.Web;
context.Load(web.Lists);
await Task.Run(() => clientContext.ExecuteQuery());
return web.Lists.Count;
}
}
它有意义吗?它有帮助吗?据我了解,我只是创建/需要一个新线程来执行查询("overhead"),但至少请求线程将空闲/准备好另一个请求(这很好)。
但这值得吗?应该这样做吗?
如果是:
Microsoft 不提供开箱即用的 "async" 方法或者他们根本不关心它,这难道不奇怪吗?
编辑:
更新为按照评论中的建议使用 Task.Run
。
这是我个人对你的问题的看法,对我来说,以上方式不是必需的。当我们在 IIS 中托管您的 API 时,服务器会从它在服务器中的线程池中分配一个线程。 IIS 也有一个设置 maxConcurrentRequestsPerCPU maxConcurrentThreadsPerCPU。您可以设置这些值来为请求提供服务,而不是完全由您自己处理请求。
However what should I do when I know a method does a web call, but it doesn't offer an async interface.
不幸的是仍然有些普遍。随着不同的库更新他们的 API,他们最终会迎头赶上。
Is it in this case worth to wrap it?
是的,如果您正在处理 UI 线程。否则,没有。
Concrete example... in my WebApi application (server)
那么,不,你不想换行 Task.Run
。正如我在 article on async
ASP.NET 中所述:
You can kick off some background work by awaiting Task.Run, but there’s no point in doing so. In fact, that will actually hurt your scalability by interfering with the ASP.NET thread pool heuristics... As a general rule, don’t queue work to the thread pool on ASP.NET.
在 ASP.NET 上用 Task.Run
换行:
- 干扰 ASP.NET 线程池试探法两次(通过现在获取一个线程然后稍后释放它)。
- 增加开销(代码必须切换线程)。
- 不释放线程(用于此请求的线程总数几乎等于只调用同步版本)。
As I understand it, I just create / need a new thread for executing the query ("overhead") but at least the request thread will be free / ready for another request (that would be good).
是的,但是您所做的只是跳线程,没有任何好处。用于阻塞查询结果的线程少了一个线程 ASP.NET 必须用来处理请求,因此通过消耗另一个线程来释放一个线程并不是一个好的权衡。
Isn't it strange that Microsoft doesn't offer the "async" method out of the box or did they just not care about it?
一些 "older" MS API 还没有开始添加 async
版本。他们当然应该,但开发人员的时间是有限的资源。
我知道您应该只对非 "CPU-intensive" 的内容使用异步,例如文件写入、网络调用等,因此我也知道将每个方法包装到 Task.Run
或类似的东西中是没有意义的。
然而,当我知道一个方法执行网络调用但它不提供异步接口时我应该怎么做。在这种情况下值得包装吗?
具体例子:
我在我的 WebApi 应用程序(服务器)中使用 CSOM(客户端 SharePoint 对象模型)并想要获取 SharePoint 列表。
这通常是这样完成的:
[HttpGet]
[Route("foo/{webUrl}")]
public int GetNumberOfLists(string webUrl)
{
using (ClientContext context = new ClientContext(webUrl))
{
Web web = context.Web;
context.Load(web.Lists);
context.ExecuteQuery();
return web.Lists.Count;
}
}
然后我想把它改成这样:
[HttpGet]
[Route("foo/{webUrl}")]
public async Task<int> GetNumberOfLists(string webUrl)
{
using (ClientContext context = new ClientContext(webUrl))
{
Web web = context.Web;
context.Load(web.Lists);
await Task.Run(() => clientContext.ExecuteQuery());
return web.Lists.Count;
}
}
它有意义吗?它有帮助吗?据我了解,我只是创建/需要一个新线程来执行查询("overhead"),但至少请求线程将空闲/准备好另一个请求(这很好)。
但这值得吗?应该这样做吗?
如果是: Microsoft 不提供开箱即用的 "async" 方法或者他们根本不关心它,这难道不奇怪吗?
编辑:
更新为按照评论中的建议使用 Task.Run
。
这是我个人对你的问题的看法,对我来说,以上方式不是必需的。当我们在 IIS 中托管您的 API 时,服务器会从它在服务器中的线程池中分配一个线程。 IIS 也有一个设置 maxConcurrentRequestsPerCPU maxConcurrentThreadsPerCPU。您可以设置这些值来为请求提供服务,而不是完全由您自己处理请求。
However what should I do when I know a method does a web call, but it doesn't offer an async interface.
不幸的是仍然有些普遍。随着不同的库更新他们的 API,他们最终会迎头赶上。
Is it in this case worth to wrap it?
是的,如果您正在处理 UI 线程。否则,没有。
Concrete example... in my WebApi application (server)
那么,不,你不想换行 Task.Run
。正如我在 article on async
ASP.NET 中所述:
You can kick off some background work by awaiting Task.Run, but there’s no point in doing so. In fact, that will actually hurt your scalability by interfering with the ASP.NET thread pool heuristics... As a general rule, don’t queue work to the thread pool on ASP.NET.
在 ASP.NET 上用 Task.Run
换行:
- 干扰 ASP.NET 线程池试探法两次(通过现在获取一个线程然后稍后释放它)。
- 增加开销(代码必须切换线程)。
- 不释放线程(用于此请求的线程总数几乎等于只调用同步版本)。
As I understand it, I just create / need a new thread for executing the query ("overhead") but at least the request thread will be free / ready for another request (that would be good).
是的,但是您所做的只是跳线程,没有任何好处。用于阻塞查询结果的线程少了一个线程 ASP.NET 必须用来处理请求,因此通过消耗另一个线程来释放一个线程并不是一个好的权衡。
Isn't it strange that Microsoft doesn't offer the "async" method out of the box or did they just not care about it?
一些 "older" MS API 还没有开始添加 async
版本。他们当然应该,但开发人员的时间是有限的资源。