我知道你应该只对非“CPU密集型”的东西使用异步,例如文件写入,Web调用等因此我也知道将每个方法包装到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;
}
}
它是否有意义并且有帮助吗?据我了解,我只是创建/需要一个新的线程来执行查询(“开销”),但至少请求线程将是空闲/准备好的另一个请求(这将是好的)。
但值得吗?应该这样做吗?
如果是这样的话: 微软不提供开箱即用的“异步”方法或他们只是不关心它并不奇怪吗?
编辑:
更新为使用评论中建议的Task.Run
。
答案 0 :(得分:5)
但是,当我知道某个方法进行网络通话时,我该怎么办,但它不提供异步接口。
不幸的是仍然有些常见。随着不同的库更新其API,它们最终将迎头赶上。
在这种情况下值得包装吗?
是的,如果您正在处理UI线程。否则,没有。
具体示例...在我的WebApi应用程序(服务器)
中
然后,不,你不想包裹Task.Run
。如我article on async
ASP.NET中所述:
你可以通过等待Task.Run开始一些后台工作,但这样做没有意义。实际上,这实际上会通过干扰ASP.NET线程池启发式来损害您的可伸缩性......作为一般规则,不要将工作排队到ASP.NET上的线程池。
在ASP.NET上使用Task.Run
包装:
据我了解,我只是创建/需要一个新线程来执行查询(“开销”),但至少请求线程可以自由/准备好进行另一个请求(这样会很好)。
是的,但你所做的只是跳线,没有任何好处。用于阻塞查询结果的线程是ASP.NET必须用来处理请求的一个线程,因此通过使用另一个线程来释放一个线程并不是一个很好的权衡。
微软不提供开箱即用的“异步”方法或他们只是不关心它并不奇怪吗?
一些“较旧的”MS API尚未添加async
版本。他们肯定应,但开发人员时间是有限的资源。
答案 1 :(得分:0)
这是我个人对您的问题的看法,对我而言,上述方式不是必需的。当我们在IIS中托管您的API时,服务器会从服务器中的线程池中分配一个线程。 IIS还具有maxConcurrentRequestsPerCPU maxConcurrentThreadsPerCPU的设置。您可以设置这些值来提供请求,而不是自己处理请求。