现有第三方Rest API可用,它接受一组输入并返回相同的输出。 (将其视为Bing的地理编码服务,它将接受地址并返回位置详细信息)
我需要的是为一个asp.net请求多次调用此API(比如500-1000),每次调用可能需要接近500毫秒才能返回。
我可以想到如何采取这种行动的三种方法。需要您的输入,这可能是保持速度作为标准的最佳方法。
1。在for循环中使用Http Request
编写一个简单的for循环,并为每个输入调用REST API并将输出添加到结果中。到目前为止,这可能是最慢的。但是没有线程或上下文切换的开销。
2。使用async并等待
使用async和await机制来调用REST Api。当等待REST调用返回时,线程继续执行其他活动可能会有效。我面临的问题是,根据建议,我应该使用等待一直到最顶层的调用者,这在我的情况下是不可能的。不遵循它可能会导致asp.net死锁,如http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
所述第3。使用任务并行库
使用Parallel.ForEach并使用Synchronuos API并行调用服务器并使用ConcurrentDictionary
保存结果。但可能导致线程开销
另外,让我知道还有其他更好的办法来处理事情。我理解人们可能会建议跟踪每种方法的性能,但是想了解人们如何解决这个问题
答案 0 :(得分:4)
最佳解决方案是使用async
和await
,但在这种情况下, 必须将async
一直带到调用堆栈对控制器的行动。
for循环使所有顺序和同步,所以它肯定是最慢的解决方案。 Parallel
将阻止每个请求多个线程,这将对您的可伸缩性产生负面影响。
由于操作是基于I / O的(调用REST API),async
是最自然的选择,应该提供这些选项的最佳整体系统性能。
答案 1 :(得分:2)
首先,我认为值得考虑一些你在问题中未提及的问题:
500-1000 API调用听起来非常多。有没有办法避免这种情况? API是否具有某种批量查询功能?或者你不能下载他们的数据库并在本地查询? (维基媒体或Stack Exchange等更开放的组织经常支持这种情况,像微软或谷歌这样的封闭组织通常不支持这种情况。)
如果这些选项不可用,那么至少考虑某种缓存,如果这对你有意义的话。
默认情况下,ASP.NET中同时允许同一服务器的并发请求数仅为10。如果您想要发出更多并发请求,则需要设置ServicePointManager.DefaultConnectionLimit
。
提出这么多请求可能会被服务提供商视为滥用,并可能导致您的IP被阻止。确保提供商可以使用这种用途。
现在,针对您的实际问题:我认为最好的选择是使用async
- await
,即使您无法一直使用它。您可以通过在每ConfigureAwait(false)
使用await
(这是正确的解决方案)或使用Task.Run(() => /* your async code here */).Wait()
之类的东西来逃避ASP.NET上下文(这是简单的解决方案)来避免死锁
使用像Parallel.ForEach()
这样的东西并不是很好,因为它不必要地浪费了ThreadPool线程。
如果你选择async
,你应该考虑限制。实现这一目标的一种简单方法是使用SemaphoreSlim
。