24

Today i tried do some optimization to foreach statement, that works on XDocument.

Before optimization:

foreach (XElement elem in xDoc.Descendants("APSEvent").ToList())
{
    //some operations
}

After optimization:

Parallel.ForEach(xDoc.Descendants("APSEvent").ToList(), elem =>
{
    //same operations
});

I saw that .NET in Parallel.ForEach(...) opened ONLY one thread! As a result the timespan of Parallel was bigger than standard foreach.

Why do you think .NET only opened 1 thread? Because of locking of file? Thanks

zzfima
  • 1,528
  • 1
  • 14
  • 21
  • 10
    How many cores or logical processors do you have in your machine? How many elements are in the list? – Christian.K Jan 19 '12 at 08:51
  • I can't see any relation of the title to the question. – Stefan Steinegger Jan 19 '12 at 09:00
  • Christian.K, i have server with Xeon processor and 8GB ram (Dell PowerEdge R210) with MS Server2008 OS. I think, it not depend on how much elements i have in XML document, i think time penalty is because of file locking. – zzfima Jan 19 '12 at 09:03
  • 1
    You may want to read through [this](http://stackoverflow.com/q/1114317/21567). – Christian.K Jan 19 '12 at 09:05
  • Stefan Steinegger, i just try to do optimization, but it not optimize at all my code! So, it is early optimization - optimization, that better not to do – zzfima Jan 19 '12 at 09:06
  • I don't think the `Parallel` class can determine the number of threads based on the collection implementation or dependency details (in your case that it is a file that _may_ need locking). There are other mechanisms in place for that (see my previous comment). – Christian.K Jan 19 '12 at 09:06
  • 1
    How do you know it's only one thread? If your code runs slower that does not mean that it was only one thread, it may be locks in your logic that may cause delay. Parallel will do its job correctly. – Akash Kava Jan 19 '12 at 09:19
  • 1
    Not related directly but interesting for people to know when to use Parallel.ForEach and when to use PLINQ: http://blog.mssoftwareconsulting.com/msswc/blog/file.axd?file=WhenToUseParallelForEachOrPLINQ.pdf – Tim Schmelter Jan 19 '12 at 09:23
  • Here are good answers on similar questions: 1.) http://stackoverflow.com/a/4172723/284240 2.) http://stackoverflow.com/a/1861694/284240 3.) http://stackoverflow.com/a/5694774/284240 – Tim Schmelter Jan 19 '12 at 09:40
  • Shouldn´t you remove the ToList() on Descendants in your optimization? – Jehof Jan 19 '12 at 11:35
  • Samuel Slade thank you for editing post name. Sorry for my poor english – zzfima Jan 23 '12 at 06:58
  • I like to know that how do we know how many threads are using parallel.foreach ti achieve the task? Just guide me. Thanks. – Thomas Nov 17 '14 at 17:43

6 Answers6

15

It's by design that Parallel.ForEach may use fewer threads than requested to achieve better performance. According to MSDN [link]:

By default, the Parallel.ForEach and Parallel.For methods can use a variable number of tasks. That's why, for example, the ParallelOptions class has a MaxDegreeOfParallelism property instead of a "MinDegreeOfParallelism" property. The idea is that the system can use fewer threads than requested to process a loop.

The .NET thread pool adapts dynamically to changing workloads by allowing the number of worker threads for parallel tasks to change over time. At run time, the system observes whether increasing the number of threads improves or degrades overall throughput and adjusts the number of worker threads accordingly.

grapeot
  • 1,594
  • 10
  • 21
  • 1
    Thanks, but that only says it _can_ open fewer threads. It doesn't explain why, other than it just felt like it. – Suncat2000 Jan 27 '20 at 22:40
2

From the problem description, there is nothing that explains why the TPL is not spawning more threads.

There is no evidence in the question that is even the problem. That can be fixed quite easily: you could log the thread id, before you enter the loop, and as the first thing you do inside your loop.

If it is always the same number, it is the TPL failing to spawn threads. You should then try different versions of your code and what change triggers the TPL to serialize everything. One reason could be if there are a small number of elements in your list. The TPL partitions your collection, and if you have only a few items, you might end up with only one batch. This behavior is configurable by the way.

It could be you are inadvertedly taking a lock in in the loop, then you will be seeing lots of different numbers, but no speedup. Then, simplify the code until the problem vanishes.

0

Not always the parallel way is faster than the "old fashion way" http://social.msdn.microsoft.com/Forums/en-US/parallelextensions/thread/c860cf3f-f7a6-46b5-8a07-ca2f413258dd

polkduran
  • 2,533
  • 24
  • 34
0

use it like this:

int ParallelThreads = 10;
Parallel.ForEach(xDoc.Descendants("APSEvent").ToList(), new ParallelOptions() { MaxDegreeOfParallelism = ParallelThreads }, (myXDOC, i, j) =>
{
 //do whatever you want here 
});
Desolator
  • 22,411
  • 20
  • 73
  • 96
  • 1
    Just note that MaxDegreeOfParallelism sets the maximum amount of threads, not the minimum. Thus, useful when you want to limit or decrease the amount of threads / cores being used. – coloboxp Apr 28 '17 at 10:44
-1

Yes exactly, Document.Load(...) locks the file and due to resource contention between threads, TPL is unable to use the power of multiple threads. Try to load the XML into a Stream and then use Parallel.For(...).

Community
  • 1
  • 1
mannu2050
  • 403
  • 3
  • 11
  • 8
    That would only explain why only one thread _makes progress_, not why only one thread is _created_ - as the OP claims. `Parallel.ForEach` cannot (sensibly) have any knowledge about the collection it is iterating (it only "sees" an `List` being passed in and it is unreasonable to assume that it has any special implementation for that). Also, `ToList` basically fetches all elements eagerly, so locking (and the fact that it is read from a file) should not make any difference here. – Christian.K Jan 19 '12 at 11:40
-1

Do you happen to have a single processor? TPL may limit the number of threads to one in this case. Same thing may happen if the collection is very small. Try a bigger collection. See this answer for more details on how the degree of parallelism is determined.

Community
  • 1
  • 1
cvlad
  • 608
  • 1
  • 6
  • 17