Estoy tratando de ejecutar varias funciones que se conectan a un sitio remoto (por red) y devuelven una lista genérica. Pero quiero ejecutarlos 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 lo veo, pueden ocurrir múltiples inserciones en 'resultados' al mismo tiempo ... Lo que puede bloquear mi aplicación.
¿Cómo puedo evitar esto?
c#
list
locking
parallel-processing
shaharmor
fuente
fuente
Respuestas:
//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.
fuente
this
no es la opción más segura para el objeto de bloqueo. Es mejor utilizar un objeto especial privado:lock(resultsLock)
.locks
Sin embargo, puede ralentizar el tiempo de ejecución general ... las colecciones concurrentes parecen ser mejores para evitar esoPuede utilizar una colección concurrente .
Puede utilizar, por ejemplo,
ConcurrentBag
ya que no tiene garantía de qué pedido se añadirán los artículos.fuente
Para aquellos que prefieren el 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; }
fuente
foreach (var item in currentProvider.SearchTitle((title))) results.Add(item);
Las colecciones concurrentes son nuevas para .Net 4; están diseñados para trabajar con la nueva funcionalidad paralela.
Consulte Colecciones simultáneas en .NET Framework 4 :
fuente
Esto podría expresarse de forma concisa utilizando PLINQ
AsParallel
ySelectMany
:public static List<SearchResult> Search(string title) { return Providers.AsParallel() .SelectMany(p => p.SearchTitle(title)) .ToList(); }
fuente
SearchTitle
conecta a un sitio remoto. Su latencia será varios órdenes de magnitud más lenta que la diferencia entre LINQ y foreach.