1

I am seeing a small performance difference between the following two functionally similar code, I hope someone will be able to help me understand why is there a difference.

//Case 1 Faster
Parallel.ForEach(data, x => func(x)) 

//Case 2 Slower
Parallel.ForEach(Partitioner.Create(data), x => func(x)) 

data is of type List<double>

As far as I understand, the default partitioning in the first case would also be similar to Partitioner.Create(data), so there should be no difference in performance.

Is there a way to figure out how the partitioning is done at runtime?

svick
  • 236,525
  • 50
  • 385
  • 514
v1p3r
  • 677
  • 7
  • 13
  • 1
    According to the msdn doc, by creating a partitioner, you load balance each thread. This creates an overhead, as the partitioner must marshall each piece of work to each thread, as they complete each previous task. If your task completes in a constant time, then you would be unlikely to have uneven load balance in the first place. In which case a static partitioning would be more appropriate. http://msdn.microsoft.com/en-us/library/dd997411(v=vs.110).aspx – Aron May 02 '14 at 07:32
  • Thanks Aron. While waiting for answers, I wrote some test code (a new wrapper class inheriting from IList and adding Console.WriteLine to each method) and I found that in the first case it is using List indexers while in the second case its using enumerators. – v1p3r May 02 '14 at 07:36
  • Why do you think that two alternatives being *similar* should imply *no difference* in performance? – svick May 03 '14 at 16:30

1 Answers1

1

I am answering my own question, in case someone is wondering about the same thing.

I wrote a new MyList class inheriting from IList and implementing all methods as wrappers around a list instance along with an additional Console.WriteLine to debug.

Interestingly, in the first case even if I pass it the IEnumerable instance, it seems to find out if it is a list underneath and it calls List's indexer functions. While in the second case it is calling GetEnumerator which I suppose is slower due to function calls and synchronization required for enumerables. The same thing happens in the first case if I pass data.Select(x=>x) instead of data.

I guess the implementation of parallel tries to find out if the IEnumerable is a List underneath and uses it if it can.

v1p3r
  • 677
  • 7
  • 13