parallel - task c# ejemplo
Lista<T> seguridad de subprocesos (6)
¡No! No es seguro en absoluto, porque processed.Add
. La 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 se creó Select
. AsParallel
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
en cada iteración obliga a una ejecución totalmente secuencial, un montón de subprocesos esperarán un único subproceso.
Estoy usando el siguiente código
var processed = new List<Guid>();
Parallel.ForEach(items, item =>
{
processed.Add(SomeProcessingFunc(item));
});
¿Es seguro el hilo del 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.
Como alternativa a la answer de Andrés:
items.AsParallel().Select(item => SomeProcessingFunc(item)).ToList();
Tambien podrias 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 fusión, MSDN . Asegúrese de que la función SomeProcessingFunc
sea segura para subprocesos. Y creo, pero no lo probé, que todavía necesita un bloqueo si la lista se puede modificar en otros elementos de un hilo (agregar o quitar).
La lectura es segura para subprocesos, pero agregar no lo es. Necesitará una configuración de bloqueo de lector / escritor, ya que la adición puede hacer que la matriz interna cambie de tamaño, lo que podría arruinar una lectura concurrente.
Si puede garantizar que la matriz no se redimensionará al agregar, puede estar seguro de agregar mientras lee, pero no me cite al respecto.
Pero en realidad, una lista es solo una interfaz para una matriz.
Para citar a Jon Skeet antes de que llegue aquí:
Como parte de Parellel Extensions en .Net 4, hay varias colecciones nuevas en un nuevo
System.Collections.Concurrent
namespace. Estos están diseñados para ser seguros frente a operaciones simultáneas de varios subprocesos, con un bloqueo relativamente pequeño.
Estos incluyen IProducerConsumerCollection<T>, BlockingCollection<T>, ConcurrentBag<T>, ConcurrentQueue<T>, ConcurrentStack<T>, and ConcurrentDictionary<TKey, TValue>
entre otros.
Utilizar:
var processed = new ConcurrentBag<Guid>();
Usando ConcurrentBag de tipo Something
var bag = new ConcurrentBag<List<Something>>;
var items = GetAllItemsINeed();
Parallel.For(items,i =>
{
bag.Add(i.DoSomethingInEachI());
});