将非异步方法(进行网络调用)包装到异步中
Posted
技术标签:
【中文标题】将非异步方法(进行网络调用)包装到异步中【英文标题】:Wrapping a non async-method (which does web calls) into async 【发布时间】:2017-07-22 05:13:41 【问题描述】:我知道您应该只对非“CPU 密集型”的东西使用异步,例如文件写入、网络调用等,因此我也知道将每个方法都包装成 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
。
【问题讨论】:
不要使用Task.Factory.StartNew
,使用Task.Run
。至于调用SharePoint,上下文有ExecuteQueryAsync
方法,可以适应返回一个Task
我正在使用的 CSOM 库中没有 ExecuteQueryAsync
.... 我更改的另一件事。
自 2010 年以来,CSOM 有一个异步 ExecuteQueryAsync 方法。您使用的是哪个 SharePoint 版本,2010、2013 还是在线?每个都有不同的 CSOM 包
您的意思是 docs 提到的方法 - 尽管我看到引用的 dll 仅适用于 Silverlight。看起来他们添加了 only there 方法,但文档页面不完整。我忘记了 API 和文档是多么直观。无论如何,CSOM 最终只是一组 REST 调用。如果您关心可伸缩性,您可以随时使用 HttpClient 或 OData。
PS - 现在你会明白为什么有些人称自己为 SharePoint 难民了
【参考方案1】:
但是,当我知道一个方法进行网络调用,但它不提供异步接口时,我该怎么办。
不幸的是,仍然有些普遍。随着不同的库更新其 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
版本。他们当然应该,但开发人员的时间是有限的资源。
【讨论】:
完美的答案,正是我“正在寻找的”——谢谢!【参考方案2】:这是我对您问题的个人看法,对我来说,上述方法不是必需的。当我们在 IIS 中托管您的 API 时,服务器会从它在服务器中的线程池中分配一个线程。 IIS 还具有 maxConcurrentRequestsPerCPU maxConcurrentThreadsPerCPU 的设置。您可以设置这些值来处理请求,而不是自己处理请求。
【讨论】:
以上是关于将非异步方法(进行网络调用)包装到异步中的主要内容,如果未能解决你的问题,请参考以下文章