What would be the best way to use a parallel task library

I just started using TPL, and I want several web service calls to happen in parallel. From what I can assemble, I see two ways to do this.

Or 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 //... }); 

Or 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. 

Apart from the correct syntax, are they equivalent?

Will they get the same result? If not, why? and which is preferable?

+7
source share
3 answers

For the discussed code and use case, both approaches are basically equivalent.

Parallel.ForEach is useful when you need to split the input range into several tasks (not applicable here) or it is easier to synchronize the merging of the results of several independent parallel operations (maybe applicable here?).

In any case, you correctly noted that in the case of Parallel.ForEach, you do not need to manually synchronize the waiting for completion, whereas if you manually run tasks, you need to manage this synchronization yourself. In this case, you are probably using something like Task.WaitAll(...) .

+5
source

Without reflection or viewing the result, I could not say for sure whether the two are the same; however, I would doubt that they are very different. The question of which is better is subjective depending on the scenario. To answer, which is preferable, again very subjective, in the scenario you quoted, I would say that I prefer Parallel.ForEach , because I can read it , but if your development team is not used in the Parallel library then the second version is the one for which you need go.

+1
source

Between the two pieces of code, Parallel.ForEach() will be more efficient, since it processes several elements in one Task one after another.

But both of them will use as many threads as ThreadPool will be, which is not very good in this case. This is because ThreadPool good at guessing the optimal number of threads if you have a very short CPU Task s, which is far from the case.

Because of this, I believe that the best option is to manually limit the degree of parallelism to a small number (you will need to measure to find out which number gives the best results):

 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 //... }); 

It would be even more efficient if you could make the web service call asynchronously. Doing this and limiting the degree of parallelism at the same time is not very simple if you are not in C # 5. If you were in C # 5 and if you also updated Proxy to support asynchronous task-based template (TAP), you can use TPL data stream for more efficient code execution:

 var actionBlock = new ActionBlock<ServiceMemberBase>( async member => { var result = await Proxy.InvokeAsync(member); //... //Do stuff with the result //... } new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 }); 
+1
source

All Articles