【发布时间】:2015-08-19 20:28:58
【问题描述】:
我已经阅读了 SO 中的所有相关问题,但对于触发多个 Web 服务调用的场景的最佳方法有点困惑。
我有一个聚合器服务,它接受输入,解析并将其转换为多个 Web 请求,进行 Web 请求调用(不相关,因此可以并行触发)并合并发送回调用者的响应。现在使用下面的代码-
list.ForEach((object obj) =>
{
tasks.Add(Task.Factory.StartNew((object state) =>
{
this.ProcessRequest(obj);
}, obj, CancellationToken.None,
TaskCreationOptions.AttachedToParent, TaskScheduler.Default));
});
await Task.WhenAll(tasks);
await Task.WhenAll(tasks) 来自 Scott Hanselman 的 post,据说
“斯蒂芬说,从可扩展性的角度来看,一个更好的解决方案是 利用异步 I/O。当你呼唤对面 网络,没有理由(除了方便)阻止 线程等待响应返回”
现有代码似乎消耗了太多线程,并且处理器时间在生产负载上飙升至 100%,这让我开始思考。
另一种替代方法是使用 Parallel.ForEach,它使用分区器但也“阻止”调用,这对我的场景来说很好。
考虑到这是所有“异步 IO”工作而不是“CPU 绑定”工作,并且 Web 请求运行时间不长(最多 3 秒返回),我倾向于相信现有代码已经足够好。但这会提供比 Parallel.ForEach 更好的吞吐量吗? Parallel.ForEach 可能使用“最少”数量的任务,因为分区和线程的最佳使用(?)。我确实用一些本地测试测试了 Parallel.ForEach,但它似乎并没有更好。
目标是减少 CPU 时间并提高吞吐量,从而提高可扩展性。是否有更好的方法来并行处理 Web 请求?
感谢任何输入,谢谢。
编辑: 代码示例中显示的 ProcessRequest 方法确实使用 HttpClient 及其异步方法来触发请求(PostAsync、GetAsync、PutAsync)。
【问题讨论】:
-
如果
ProcessRequest使用异步方法,为什么要在Task.Factory.StartNew内部调用它?您可以简单地将它返回的任务添加到您的列表中。如果您实际上在其中阻塞,则在其中的某些部分使用异步方法并不重要。最后的阻塞调用否定了任何好处 -
“除了方便”很好,这是一个很好的理由。
标签: c# multithreading parallel-processing task-parallel-library parallel.foreach