2011-11-03 9 views
48

Sto provando a eseguire più funzioni che si collegano a un sito remoto (tramite rete) e restituiscono un elenco generico. Ma voglio eseguirli contemporaneamente.Parallel.ForOgni con aggiunta all'elenco

Ad esempio:

public static List<SearchResult> Search(string title) 
{ 
    //Initialize a new temp list to hold all search results 
    List<SearchResult> results = new List<SearchResult>(); 

    //Loop all providers simultaneously 
    Parallel.ForEach(Providers, currentProvider => 
    { 
     List<SearchResult> tmpResults = currentProvider.SearchTitle((title)); 

     //Add results from current provider 
     results.AddRange(tmpResults); 
    }); 

    //Return all combined results 
    return results; 
} 

come la vedo io, più inserimenti a 'risultati' possono gionro allo stesso tempo ... Il che può bloccare la mia domanda.

Come posso evitare questo?

+0

Quale versione .NET stai usando? – sll

+3

Dovrebbe essere almeno .Net 4; Parallelamente è stato introdotto lì. – arootbeer

risposta

36
//In the class scope: 
Object lockMe = new Object();  

//In the function 
lock (lockMe) 
{  
    results.AddRange(tmpResults); 
} 

Fondamentalmente un lucchetto significa che solo una discussione può accedere a quella sezione critica allo stesso tempo.

+0

Ma cosa succederà se MENTRE quei risultati vengono aggiunti i risultati di un altro provider tenta di aggiungere a? saranno FALLISCI o ATTENDONO fino a quando possibile? – shaharmor

+3

Quando c'è un blocco, il thread attenderà fino a quando non sarà possibile ottenere il blocco. – Haedrian

+0

Quindi in pratica è come dire: Attendi fino a quando! Results.isLocked, e quando è libero lo blocca e scrive? – shaharmor

21

Le raccolte simultanee sono nuove per .Net 4; sono progettati per funzionare con la nuova funzionalità parallela.

Vedi Concurrent Collections in the .NET Framework 4:

Prima .NET 4, era necessario fornire i propri meccanismi di sincronizzazione se più thread possono accedere ai un'unica raccolta condivisa. Hai dovuto bloccare la raccolta ...

... le [nuove] classi e interfacce in System.Collections.Concurrent [aggiunto in .NET 4] forniscono un'implementazione coerente per la [...] programmazione multi-threaded problemi che coinvolgono dati condivisi tra thread.

94

È possibile utilizzare uno concurrent collection.

Il System.Collections.Concurrent namespace fornisce diverse classi di raccolta thread-safe che devono essere utilizzati al posto dei tipi corrispondenti nelle System.Collections e System.Collections.Generic namespace quando più thread accedono contemporaneamente alla raccolta.

È possibile ad esempio utilizzare ConcurrentBag poiché non si è certi dell'ordine in cui verranno aggiunti gli articoli.

Rappresenta una raccolta di oggetti non protetta da thread.

+3

Questo dovrebbe essere contrassegnato come risposta! – Misiu

+0

Sì, questa è la risposta effettiva. Otterrai prestazioni migliori (generalmente) con raccolte simultanee. – lkg

+0

segna come risposta! – Serdar

10

Questo potrebbe essere espresso in modo conciso utilizzando del PLINQ AsParallel e SelectMany:

public static List<SearchResult> Search(string title) 
{ 
    return Providers.AsParallel() 
        .SelectMany(p => p.SearchTitle(title)) 
        .ToList(); 
} 
14

Per chi preferisce il codice:

public static ConcurrentBag<SearchResult> Search(string title) 
{ 
    var results = new ConcurrentBag<SearchResult>(); 
    Parallel.ForEach(Providers, currentProvider => 
    { 
     results.Add(currentProvider.SearchTitle((title))); 
    }); 

    return results; 
}