2011-11-03 4 views
48

Estoy tratando de ejecutar múltiples funciones que se conectan a un sitio remoto (por red) y devolver una lista genérica. Pero quiero ejecutarlos simultáneamente.Parallel.ForEach con agregar a la lista

Por ejemplo:

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; 
} 

Tal como lo veo, múltiples inserciones a 'resultados' pueden acaecer al mismo tiempo ... ¿Qué se puede bloquear mi solicitud.

¿Cómo puedo evitar esto?

+0

Qué versión .NET está usando? – sll

+3

Tendría que ser al menos .Net 4; Paralelo fue presentado allí. – arootbeer

Respuesta

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

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

Básicamente un bloqueo significa que solo un hilo puede tener acceso a esa sección crítica al mismo tiempo.

+0

Pero, ¿qué pasará si MIENTRAS esos resultados se agregan los resultados de otro proveedor intentan agregar? ¿FALLARÁN o ESPERA hasta que sea posible? – shaharmor

+3

Cuando hay un bloqueo, el hilo esperará hasta que pueda obtener el bloqueo. – Haedrian

+0

Así que básicamente es como decir: Espere hasta que! Results.isLocked, y cuando se bloquea y escriba? – shaharmor

21

Las colecciones concurrentes son nuevas para .Net 4; están diseñados para funcionar con la nueva funcionalidad paralela.

Ver Concurrent Collections in the .NET Framework 4:

Antes de .NET 4, había que proporcionar sus propios mecanismos de sincronización si varios subprocesos pueda estar accediendo a una única colección compartida. Debes bloquear la colección ...

... las [nuevas] clases e interfaces en System.Collections.Concurrent [agregado en .NET 4] proporcionan una implementación consistente para la programación de subprocesos múltiples. problemas que involucran datos compartidos entre hilos.

94

Puede usar un concurrent collection.

El System.Collections.Concurrent espacio de nombres proporciona varias clases de colección de hilo de seguridad que se deben utilizar en lugar de los tipos correspondientes de los System.Collections y System.Collections.Generic espacios de nombres siempre que múltiples hilos están accediendo a la colección concurrentemente.

Podría, por ejemplo, usar ConcurrentBag ya que no tiene garantía en qué orden se agregarán los artículos.

Representa una colección de objetos desordenada y segura para subprocesos.

+3

¡Esto debe marcarse como respuesta! – Misiu

+0

Sí, esta es la respuesta real. Obtendrá un mejor rendimiento (generalmente) con colecciones simultáneas. – lkg

+0

marque como respuesta! – Serdar

10

Esto podría expresarse de forma concisa utilizando de PLINQ AsParallel y SelectMany:

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

Para aquellos que prefieren código:

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

    return results; 
} 
Cuestiones relacionadas