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.
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.ForEach
se 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.
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>();
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.
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.
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());
});
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.
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