Próbuję uruchomić wiele funkcji, które łączą się ze zdalną lokalizacją (przez sieć) i zwracają listę ogólną. Ale chcę je uruchamiać jednocześnie.
Na przykład:
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;
}
Jak widzę, wiele wstawień do „wyników” może mieć miejsce w tym samym czasie ... co może spowodować awarię mojej aplikacji.
Jak mogę tego uniknąć?
c#
list
locking
parallel-processing
shaharmor
źródło
źródło
Odpowiedzi:
//In the class scope: Object lockMe = new Object(); //In the function lock (lockMe) { results.AddRange(tmpResults); }
Zasadniczo blokada oznacza, że tylko jeden wątek może mieć dostęp do tej krytycznej sekcji w tym samym czasie.
źródło
this
nie jest najbezpieczniejszym wyborem dla obiektu zamka. Lepiej użyć specjalnego prywatny obiekt:lock(resultsLock)
.locks
może jednak spowolnić ogólny czas realizacji .. równoległe kolekcje wydają się lepsze, aby tego uniknąćMożesz użyć kolekcji współbieżnej .
Możesz na przykład użyć,
ConcurrentBag
ponieważ nie masz gwarancji, w jakiej kolejności pozycje zostaną dodane.źródło
Dla tych, którzy wolą kod:
public static ConcurrentBag<SearchResult> Search(string title) { var results = new ConcurrentBag<SearchResult>(); Parallel.ForEach(Providers, currentProvider => { results.Add(currentProvider.SearchTitle((title))); }); return results; }
źródło
foreach (var item in currentProvider.SearchTitle((title))) results.Add(item);
Kolekcje współbieżne są nowością w .Net 4; są zaprojektowane do pracy z nową funkcją równoległą.
Zobacz kolekcje współbieżne w .NET Framework 4 :
źródło
Można to zwięźle wyrazić za pomocą PLINQ
AsParallel
iSelectMany
:public static List<SearchResult> Search(string title) { return Providers.AsParallel() .SelectMany(p => p.SearchTitle(title)) .ToList(); }
źródło
SearchTitle
łączy się ze zdalną lokalizacją. Jego opóźnienie będzie o kilka rzędów wielkości wolniejsze niż różnica między LINQ i foreach.