Lista de seguridad del hilo


Estoy usando el siguiente código

var processed = new List<Guid>();
Parallel.ForEach(items, item => 
{
    processed.Add(SomeProcessingFunc(item));
});

¿Es seguro el hilo de código anterior? ¿Existe la posibilidad de que la lista procesada se corrompa? ¿O debo usar un candado antes de agregar?

var processed = new List<Guid>();
Parallel.ForEach(items, item => 
{
    lock(items.SyncRoot)
        processed.Add(SomeProcessingFunc(item));
});

Gracias.

Author: stackoverflowuser, 2011-02-16

6 answers

¡No! No es seguro en absoluto, porque processed.Add no lo es. Puedes hacer lo siguiente:

items.AsParallel().Select(item => SomeProcessingFunc(item)).ToList();

Tenga en cuenta que Parallel.ForEachse creó principalmente para operaciones imperativas para cada elemento de secuencia. Lo que haces es mapear: proyectar cada valor de secuencia. Para eso fue creado Select. AsParallel lo escala a través de hilos de la manera más eficiente.

Este código funciona correctamente:

var processed = new List<Guid>();
Parallel.ForEach(items, item => 
{
    lock(items.SyncRoot)
        processed.Add(SomeProcessingFunc(item));
});

Pero no tiene sentido en términos de multihilo. lock ing en cada iteración fuerza totalmente ejecución secuencial, montón de subprocesos estará esperando un solo subproceso.

 25
Author: Andrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-16 18:25:35

Uso:

var processed = new ConcurrentBag<Guid>();

Ver comportamiento paralelo del bucle foreach - impar.

 6
Author: mellamokb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:50

Para citar a Jon Skeet antes de llegar aquí:

Como parte de las extensiones Parellel en. Net 4, hay varias nuevas colecciones en un nuevo System.Collections.Concurrent espacio de nombres. Estos están diseñados para ser seguro en la cara de concurrente operaciones de múltiples hilos, con relativamente poco bloqueo.

Estos incluyen IProducerConsumerCollection<T>, BlockingCollection<T>, ConcurrentBag<T>, ConcurrentQueue<T>, ConcurrentStack<T>, and ConcurrentDictionary<TKey, TValue> entre otros.

 4
Author: DOK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-16 18:27:14

Como alternativa a la respuesta de Andrey:

items.AsParallel().Select(item => SomeProcessingFunc(item)).ToList();

También podrías escribir

items.AsParallel().ForAll(item => SomeProcessingFunc(item));

Esto hace que la consulta que está detrás de ella sea aún más eficiente porque no se requiere una combinación, MSDN. Asegúrese de que la función SomeProcessingFunc es segura para subprocesos. Y creo, pero no lo probé, que todavía necesita un bloqueo si la lista se puede modificar en otro subproceso (agregar o eliminar) elementos.

 1
Author: Christophe Lambrechts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:02

Usando ConcurrentBag de tipo Something

var bag = new ConcurrentBag<List<Something>>;
var items = GetAllItemsINeed();
Parallel.For(items,i =>                          
   {
      bag.Add(i.DoSomethingInEachI());
   });
 1
Author: John Peters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-24 17:07:26

La lectura es segura para el hilo, pero la adición no lo es. Necesita una configuración de bloqueo de lector/escritor, ya que agregar puede hacer que la matriz interna cambie de tamaño, lo que arruinaría una lectura simultánea.

Si puede garantizar que la matriz no redimensionará al agregar, puede ser seguro agregar mientras lee, pero no me cite en eso.

Pero en realidad, una lista es solo una interfaz para una matriz.

 0
Author: Bengie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-16 18:39:35