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

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

Como yo lo veo, múltiples inserciones para los ‘resultados’ de mayo ha ocurrido al mismo tiempo… Que puede bloquearse mi aplicación.

¿Cómo puedo evitar esto?

  • Que .NET versión estás usando?
  • Tendría que ser al menos .Net 4; en Paralelo se presentó allí.
InformationsquelleAutor shaharmor | 2011-11-03

5 Comentarios

  1. 49
    //In the class scope:
    Object lockMe = new Object();    
    
    //In the function
    lock (lockMe)
    {    
         results.AddRange(tmpResults);
    }

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

    • Pero, ¿qué sucede si MIENTRAS que los resultados se agregan los resultados de otro proveedor a tratar de añadir a? le FALLAN o ESPERAR hasta que sea posible?
    • Cuando hay un bloqueo, el hilo va a esperar hasta que pueda conseguir el bloqueo.
    • Así que, básicamente, es como decir: Esperar hasta que el !resultados.isLocked, y cuando su libre bloquearlo y escribir?
    • Los bloqueos de trabajo en trozos de código no sobre las variables. Usted puede poner mucho más código. Es importante darse cuenta de que. La cerradura no proteger a la variable fuera de la cerradura. Básicamente, el hilo va a esperar en la cerradura, si el candado está cerrado, se va a esperar. Si no, te bloqueo por sí mismo, y entrar en esa sección. Luego, cuando su hecho libera el bloqueo y otros hilos pueden entrar. Si necesita más flexibilidad existen otros tipos de bloqueos, pero esto funcionará para usted.
    • Ok muchas gracias eso es exactamente lo que estaba buscando!
    • Un punto menor: this no es la opción más segura para el objeto de bloqueo. Mejor usar un especial de objeto privado: lock(resultsLock) .
    • locks puede ralentizar el tiempo total de ejecución aunque.. concurrente colecciones parecen mejor para evitar que
    • ¿Por qué necesitamos un bloqueo a nivel de clase, si el objeto modificado es declarado localmente ? Si nos lock(results) y, a continuación, añadir a lo que está mal ? Bloqueo a nivel de clase significa, si varias solicitudes están llamando Search, a continuación, usted ha degradado el rendimiento

  2. 135

    Puede utilizar un concurrente de la colección.

    La System.Collections.Concurrent espacio de nombres proporciona varios subprocesos de la colección de clases que se debe utilizar en lugar de los tipos correspondientes en el System.Collections y System.Collections.Generic espacios de nombres cuando varios subprocesos son el acceso a la colección al mismo tiempo.

    Por ejemplo, podría utilizar ConcurrentBag ya que no hay garantía de que el orden de los artículos se añadirán.

    Representa un hilo de seguridad, colección desordenada de objetos.

    • Este debe ser marcado como respuesta!
    • Sí, esta es la respuesta real. Usted obtendrá un mejor rendimiento (en general) con las colecciones simultáneas.
  3. 22

    Concurrente de las Colecciones son nuevos para .Net 4; están diseñados para trabajar con la nueva funcionalidad paralela.

    Ver Las Colecciones simultáneas en el .NET Framework 4:

    Antes .NET 4, había que proporcionar sus propios mecanismos de sincronización si varios hilos podría tener acceso a una sola colección compartida. Había que bloquear la colección …

    … el [nuevo] clases e interfaces en el Sistema.Las colecciones.Concurrente [agregado en .NET 4] proporcionar una implementación coherente para […] multi-threaded programación de los problemas que implican datos compartidos a través de los subprocesos.

  4. 21

    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;
    }
  5. 12

    Se podría expresar de manera concisa con PLINQ del AsParallel y SelectMany:

    public static List<SearchResult> Search(string title)
    {
        return Providers.AsParallel()
                        .SelectMany(p => p.SearchTitle(title))
                        .ToList();
    }
    • linq selectMany es grande, lamentablemente linq es más lento de lo normal foreach. 🙁
    • No micro-optimizar. El OP implícita que SearchTitle se conecta a un sitio remoto. Su latencia va a ser de varios órdenes de magnitud más lenta que la diferencia entre LINQ y foreach.

Dejar respuesta

Please enter your comment!
Please enter your name here