2013-05-07 9 views
18

Qualcuno sa di un modo per ottenere il ciclo Parallel.Foreach per utilizzare il partizionamento del blocco contro, cosa che credo sia il partizionamento dell'intervallo per impostazione predefinita. Sembra semplice quando si lavora con gli array perché è possibile semplicemente creare un partizionatore personalizzato e impostare il bilanciamento del carico su true.Partizionamento di blocchi IEnumerable in Parallel.Foreach

Poiché il numero di elementi in un oggetto IEnumerable non è noto fino al runtime, non riesco a trovare un buon modo per far funzionare il partizionamento del blocco.

Qualsiasi aiuto sarebbe apprezzato.

grazie!

Le attività che sto tentando di eseguire su ciascun oggetto richiedono tempi significativamente diversi per l'esecuzione. Alla fine di solito sono le ore in attesa che l'ultimo thread finisca il suo lavoro. Quello che sto cercando di ottenere è di avere i blocchi di richiesta del loop parallelo lungo il percorso invece di pre-allocare gli elementi in ogni thread.

+0

Perché vuoi che questo (fuori interesse) –

+0

Lo fai a pezzi per numero di pezzi o per dimensione per pezzo? – SimpleVar

+0

Hai un oggetto IEnumerable o hai qualcosa che implementa un indicizzatore (quindi potresti fare 'obj [i]' su di esso? Se riesci a passare un indice, ho una soluzione. –

risposta

19

Se l'IEnumerable è stato davvero qualcosa che avesse un un indicizzatore (vale a dire che si potrebbe fare obj[1] per ottenere una voce fuori) si potrebbe fare la seguente

var rangePartitioner = Partitioner.Create(0, source.Length); 
    Parallel.ForEach(rangePartitioner, (range, loopState) => 
    { 
     // Loop over each range element without a delegate invocation. 
     for (int i = range.Item1; i < range.Item2; i++) 
     { 
      var item = source[i] 
      //Do work on item 
     } 
    }); 

Tuttavia, se non si può fare questo è necessario scrivere un partizionatore personalizzato creando una nuova classe derivata da System.Collections.Concurrent.Partitioner<TSource>. Quel soggetto è troppo ampio per rispondere in una risposta SO, ma puoi dare un'occhiata a this guide on the MSDN per iniziare.

UPDATE: Come di .NET 4.5 hanno aggiunto un sovraccarico di Partitioner.Create che non buffer dei dati, ha lo stesso effetto di rendere un partizionamento personalizzato con una dimensione massima di gamma 1. Con questo non sarà possibile ottenere una thread singolo che ha un sacco di lavoro in coda se è stato sfortunato con un mucchio di oggetti lenti di fila.

var partitoner = Partitioner.Create(source, EnumerablePartitionerOptions.NoBuffering); 
Parallel.ForEach(partitoner, item => 
{ 
    //Do work 
}