我刚刚开始使用TPL,我希望对Web服务进行多次并行调用。从我可以收集的信息中,我看到了两种方法。
Parallel.ForEach
:
List<ServiceMemberBase> list = new List<ServiceMemberBase>(); //Take list from somewhere.
Parallel.ForEach(list, member =>
{
var result = Proxy.Invoke(member);
//...
//Do stuff with the result
//...
});
或Task<T>
:
List<ServiceMemberBase> list = new List<ServiceMemberBase>(); //Take list from somewhere.
ForEach(var member in list)
{
Task<MemberResult>.Factory.StartNew(() => proxy.Invoke(member));
}
//Wait for all tasks to finish.
//Process the result objects.
无论语法是否正确,这些都是等效的吗?
他们会产生相同的结果吗?如果没有,为什么?哪个更好?
答案 0 :(得分:5)
对于您讨论的代码和用例,这两种方法基本相同。
当你必须在几个任务上划分输入范围(这里不适用)时,Parallel.ForEach很有用,或者更容易同步几个独立并行操作的结果的合并(这里可能适用?)。
在任何情况下,您都已正确注意到在Parallel.ForEach情况下,您不必手动同步等待完成,而如果手动启动任务,则必须自己管理该同步。在这种情况下,您可能会使用类似Task.WaitAll(...)
的内容。
答案 1 :(得分:1)
如果没有反映或查看输出,我无法确定两者是否相同;但我怀疑它们是否有那么大的不同。关于哪个更好的问题取决于场景是主观的。回答哪个更好是再次非常主观,在你提供的场景中我会说我更喜欢Parallel.ForEach 因为我可以读它但是如果你的开发团队不习惯并行库然后是第二个版本。
答案 2 :(得分:1)
在两段代码之间,Parallel.ForEach()
会更有效率,因为它会一个接一个地处理单个Task
中的多个项目。
但是他们两个都会使用尽可能多的线程,因为ThreadPool
会允许它们,在这种情况下这不是一个好主意。那是因为ThreadPool
擅长猜测最佳线程数,如果你有非常短的,受CPU限制的Task
s,这远不是这里的情况。
因此,我认为最好的选择是手动将并行度限制为一小部分(您必须进行测量才能找出最佳结果的数字):
List<ServiceMemberBase> list = …; //Take list from somewhere.
Parallel.ForEach(list, new ParallelOptions { MaxDegreeOfParallelism = 10 },
member =>
{
var result = Proxy.Invoke(member);
//...
//Do stuff with the result
//...
});
如果您可以异步执行Web服务调用,效率会更高。这样做并同时限制并行度并不容易,除非您使用的是C#5。如果您使用的是C#5,并且还更新了Proxy
以支持基于任务的异步模式( TAP),您可以使用TPL Dataflow更有效地执行代码:
var actionBlock = new ActionBlock<ServiceMemberBase>(
async member =>
{
var result = await Proxy.InvokeAsync(member);
//...
//Do stuff with the result
//...
}
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 });