44

Is there any difference between the below code snippets. If so, what?

myList.AsParallel().ForAll(i => { /*DO SOMETHING*/ });

and

Parallel.ForEach(mylist, i => { /*DO SOMETHING*/ });

Will the main thread wait for all the child threads to complete? In a MVC application, if I'm doing parallel processing in my controller action, what happens to the child threads after the main thread completes. Will they be aborted or will they be completed even after the main thread is completed?

Aran Mulholland
  • 23,555
  • 29
  • 141
  • 228
Dhawal
  • 1,240
  • 2
  • 12
  • 20
  • 1
    I suggest you to read: http://reedcopsey.com/2010/02/03/parallelism-in-net-part-8-plinqs-forall-method/ – e_ne Jan 08 '13 at 01:19
  • 4
    If I were you, I would open another question for your MVC parallel processing thingy. – Pacane Jan 08 '13 at 01:33
  • Please be careful of AsParallel().ForAll() as it causes unpredictive result. For example I have a button to execute this code when clicked: myEnumerable.AsParallel().ForAll(i as string => otherDictionary.Add(i, 0)) . It will add null as a key to otherDictionary. I had to rewrote to use foreach loop. Weird. – YukiSakura Dec 22 '15 at 08:16
  • 2
    @YukiSakura, Maybe you weren't using a ConncurrentDictionary? I think we should not be afraid use use code because of a comment without a full example. It would be better to post your issue as a separate question. – crokusek Feb 21 '17 at 23:09

4 Answers4

24

Parallel.ForEach() is intended exactly for this kind of code.

On the other hand, ForAll() is intended to be used at the end of a (possibly complex) PLINQ query.

Because of that, I think Parallel.ForEach() is the better choice here.

In both cases, the current thread will be used to perform the computations (along with some threads from the thread pool) and the method will return only after all processing has been completed.

svick
  • 236,525
  • 50
  • 385
  • 514
  • 4
    Why is ForAll() intended to be used at the end of a PLINQ query? – Aran Mulholland Apr 01 '14 at 06:59
  • 2
    @AranMulholland According to [Reed Copsey](http://reedcopsey.com/2010/02/03/parallelism-in-net-part-8-plinqs-forall-method/) a parallel query that is consumed by Parallel.Foreach() has to pay the cost for parallization twice. Whereas ForAll() uses existing partitions/threads from the query. – Kabbalah Apr 29 '14 at 15:27
  • 1
    I guess that since `Parallel.ForEach()` is from the `System.Threading.Tasks` namespace then it is more likely related to tasks. While `AsParallel().ForAll` is from the `System.Linq` namespace and so is more likely to be better used with PLINQ. – Ben Nov 28 '14 at 17:34
  • 1
    @Ben I don't quite understand `ForAll` is part of PLINQ. And I don't know what "related to tasks" means. – svick Nov 28 '14 at 19:16
4

Here is an explanation in MSDN:

https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/potential-pitfalls-with-plinq#prefer-forall-to-foreach-when-it-is-possible

Based on what I read, use Parallel.ForEach() if you want to ensure the list are access sequentially while using AsParallel.ForAll() does not guarantee the items in the list are accessed in order.

For MVC, all thread are request-based. The caller thread (main) is blocked until the Parallel() call is completed, that means all child threads should have completed as well.

If the caller thread is aborting, here is an explain:

http://www.albahari.com/threading/part5.aspx

PLINQ doesn't preemptively abort threads, because of the danger of doing so. Instead, upon cancellation it waits for each worker thread to finish with its current element before ending the query. This means that any external methods that the query calls will run to completion.

dsum
  • 1,433
  • 1
  • 14
  • 29
  • *"Based on what I read, use Parallel.ForEach() if you want to ensure the list are access sequentially"* - That's completely wrong and does not deserve to be upvoted. You completely misunderstood the referenced article. As the name "parallel" implies the items are not enumerated sequentially. Of course `Parallel.ForEach` enumerates the source collection in *parallel* i.e. out of sequential order, therefore producing an unordered result. –  Jul 08 '23 at 10:23
  • `ForAll` only applies to PLINQ (`Parallel.ForEach` is not PLINQ)! If you don't explicitly call `ParallelEnumerable.ForAll` the PLINQ query is in fact enumerated in parallel but then the query results are merged back sequentially using a common `foreach` iterator (in order to preserve the original order). ` –  Jul 08 '23 at 10:23
  • Parallel.ForEach` will always enumerate the collection in parallel producing an unordered result. The example in the posted link tries to convert the sequential enumeration (merging) back to a parallel enumeration by passing the PLINQ query result (a `ParallelEnumerable`) to a `Parallel.ForEach`. For performance reasons you should not pass the PLINQ query to a `Parallel.ForEach` but instead call `ForAll` on the `ParallelEnumerable` query object. `ForAll` skips the merging part from the PLINQ query. –  Jul 08 '23 at 10:25
4

As written in Concurrency in C# Cookbook:

One difference between Parallel and PLINQ is that PLINQ assumes it can use all of the cores on the computer, while Parallel will dynamically react to changing CPU conditions.

-1

You have the option to order the elements with AsParallel().AsOrdered(). Ordering in Parallel.ForEach is not out of box, we need do it.

thewpfguy
  • 794
  • 6
  • 15
  • `AsOrdered()` affects the ordering of *results*. And since `ForAll()` doesn't have any results, `AsOrdered()` won't have any effect here. If you're talking about ordering of processing, that makes sense only for single-threaded computations. – svick Nov 28 '14 at 19:17
  • Am I saying you use ForAll() with AsOrdered()? Please check. – thewpfguy Jan 09 '15 at 03:51
  • Sorry, my mistake. But using AsOrdered with Parallel.ForEach makes even less sense, the original non-parallel collection is already ordered, so adding .AsParallel().AsOrdered() won't have any effect. Besides, trying to order parallel computations rarely makes sense. – svick Jan 09 '15 at 11:43