Domanda

Vorremmo costruire un modello attorno a determinati anelli nella nostra soluzione, che permetterà loro di correre in seriale o parallelo, a seconda dei fattori.Di seguito è riportata la forma generale.

Dal momento che le collezioni simultanee non condividono un'interfaccia comune con le collezioni regolari, abbiamo bisogno di una sorta di adattatore per scrivere codice generale.

Specificamente attorno all'utilizzo del delegato addFunc nel corpo del loop, c'è qualcosa che finisse per causare problemi a lungo termine che potremmo perdere?Funziona fino ad ora, ma ....?

Action<SomeType> addFunc;

if(runInParallel)
{
   addFunc = concurrentBag.Add;
   loopDelegate = Parallel.ForEach;
}
else
{
   addFunc = iList.Add;
   loopDelegate = Serial.ForEach; // wrapper delegate for foreach
}

loopDelegate(source, item =>
{
   SomeType result = longRunningTask(item);
   ...
   addFunc(result); // will this 
});
.

È stato utile?

Soluzione

Curioso perché non usare TPL in .NET 4.0? http://msdn.microsoft.com/en-us/library/dd537609.aspx

C'è un eccellente carta bianca delle considerazioni che hanno adottato quando si sviluppano TPL, se non è possibile utilizzare .NET 4, dovresti guardare la carta e considerare alcuni dei Gotcha in là.

Aggiornato in base al commento sottolineando l'ovvio.

Userei qualche zucchero sintattico come,

ForEach<Tsource>(Predicate<IEnumerable<TSource>> isParallel, IEnumerable<TSource> source, Action<TSource> body)
{
    if(isParallel(source))
    {
        Parallel.ForEach<TSource>(source, body);
    }
    else
    {
        foreach (TSource element in source)
        {
            body(element);
        }
    }
}
.

Ci sono due vantaggi principali sulla tua implementazione.

    .
  1. Si enumerai due volte, una volta per aggiungere gli articoli da loop e un 2 ° tempo durante l'esecuzione.
  2. Non è immediatamente ovvio, ma ti stai fermando parallele. Parallel.Foreach non userà sempre Getenumerator in Ienumerable. Un enumeratore di Design non è simultaneo, se il tuo articolo implementa ilist, parallelo.FOREACH utilizzerà l'indicizzatore per consentire a ciascun thread di accedere all'elemento nella sorgente senza attendere l'enumeratore per iterano attraverso l'elenco. Concurrentbag non implementa ilist.

    Questa è la carta che mi riferivo a BTW, http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=19222 .

    È tutto un ottimo lettura se stai implementando questo, ma presta particolare attenzione, Pagine 1 [5-7], 26, 3 [0-2].

    Lo zucchero sintattico significa che puoi chiamarlo come faresti con TPL,

    MyParllelLibrary.ForEach( (list) => true, list), item =>
    {
        // What my code does
    });
    
    .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top