Lal*_*man 8 c# parallel-processing multithreading task-parallel-library parallel.foreach
我已经阅读了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);
Run Code Online (Sandbox Code Playgroud)
在await Task.WhenAll(tasks)来自斯科特Hanselman的帖子在那里说,
斯蒂芬说:"从可伸缩性的角度来看,更好的解决方案是利用异步I/O.当你通过网络呼叫时,没有理由(除了方便之外)在等待响应来阻止线程时背部"
现有代码似乎消耗了太多线程,并且处理器时间在生产负载上高达100%,这让我思考.
另一个替代方法是使用Parallel.ForEach,它使用分区器,但也"阻塞"调用,这对我的场景来说很好.
考虑到这是所有"异步IO"工作而不是"CPU绑定"工作,并且Web请求不会长时间运行(最多返回3秒),我倾向于认为现有代码足够好.但是这会提供比Parallel.ForEach更好的吞吐量吗?Parallel.ForEach可能使用"最小"数量的任务,因为分区因此最佳使用线程(?).我用一些本地测试测试了Parallel.ForEach,它似乎没有更好.
目标是减少CPU时间并提高吞吐量,从而提高可扩展性.是否有更好的方法来并行处理Web请求?
感谢任何投入.
编辑: 代码示例中显示的ProcessRequest方法确实使用HttpClient及其异步方法来触发请求(PostAsync,GetAsync,PutAsync).
进行Web请求调用(不相关,因此可以并行触发)
你真正需要的是给他们打电话的同时,不平行.也就是说,"同时",而不是"使用多个线程".
现有代码似乎消耗了太多线程
是的,我也这么认为.:)
考虑到这是所有"异步IO"工作而不是"CPU绑定"工作
然后它应该全部异步完成,而不是使用任务并行或其他并行代码.
正如Antii指出的那样,您应该使异步代码异步:
public async Task ProcessRequestAsync(...);
Run Code Online (Sandbox Code Playgroud)
那么你想要做的是使用异步并发(Task.WhenAll)而不是并行并发(StartNew/ Run/ Parallel)来使用它:
await Task.WhenAll(list.Select(x => ProcessRequestAsync(x)));
Run Code Online (Sandbox Code Playgroud)