4
// parameters.Count == 10
// actualFreeLicenses == 2
Parallel.For(0, parameters.Count, new ParallelOptions() 
                    {
                        MaxDegreeOfParallelism = actualFreeLicenses
                    }, i =>
                    {
                        ExternalProgram(i);
                    }
);

When I execute the above code I notice that the value of i passed to the ExternalProgram method are 1 & 6, later 2 & 7, later 3 & 8 ...

If I have 14 Parameters and 2 licenses it always launch 1 & 8, later 2 & 9 ...

Is it possible to define order: first 1 & 2, later 3 & 4 etc?

Greg B
  • 13,819
  • 18
  • 78
  • 132
Saint
  • 5,127
  • 22
  • 57
  • 99

5 Answers5

10

How about using a Queue/ConcurrentQueue and dequeueing items in the body of your parallel loop? This will ensure that ordering is preserved.

spender
  • 106,080
  • 28
  • 202
  • 324
4

If you are using Parallel the order in which they are executed is not of relevance therefore "Parallel". You should use a sequential workflow if the order is relevant for you.

oberfreak
  • 1,761
  • 13
  • 20
  • ExternalProgram(i) take a lot of time so I need multithreading. Sometimes I have more free licenses. And sequence is not necessary but will be useful – Saint Sep 29 '11 at 09:57
  • @Saint, and cant you use `Task` with [`ContinueWith`](http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.continuewith.aspx) to run some sequences after thread has done its work? – 0x49D1 Sep 29 '11 at 10:01
  • 1
    You could use a Queue for the sequence of the Items, and multiple threads which are requesting their Items from this Queue. So you could decide how may threads and in which order. Please don't forget to Lock the access to the Queues. – oberfreak Sep 29 '11 at 10:54
  • 1
    @oberfreak: ... or use ConcurrentQueue – spender Sep 29 '11 at 11:55
2

It sounds like you might want to use Parallel.ForEach with a custom partitioner instead - but don't forget that it's not really doing "1 & 6, then 2 & 7" - it's doing (say) 1 on thread 1, 6 on thread 2, then 7 on thread 2, etc. It's not launching pairs of processes as such.

If you want to launch groups of processes, you should probably perform the grouping yourself, then loop over those groups in series, only providing the parallelism within the group, by specifying a maximum degree of parallelization equal to the group size.

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
1

If you could switch to using a ForEach (after having generated a range of numbers, perhaps, using IEnumerable.Range), you could use one of the overloads that takes a Partitioner<T>. That third link includes a sample partitioner that provides a single element at a time.

Damien_The_Unbeliever
  • 220,246
  • 21
  • 302
  • 402
0

It would appear that the runtime is looking at how many threads you want to use and dividing the workload up into that. e.g. the first thread is working on the first half of the dataset and the second thread is working on the second half of the data.

Greg B
  • 13,819
  • 18
  • 78
  • 132