Próbuję zrozumieć, dlaczego Parallel.For jest w stanie przewyższyć liczbę wątków w następującym scenariuszu: rozważ partię zadań, które mogą być przetwarzane równolegle. Podczas przetwarzania tych zadań można dodawać nowe prace, które również muszą zostać przetworzone. Rozwiązanie Parallel.For
będzie wyglądać następująco:Równolegle.Nie w stosunku do zwykłych wątków
var jobs = new List<Job> { firstJob };
int startIdx = 0, endIdx = jobs.Count;
while (startIdx < endIdx) {
Parallel.For(startIdx, endIdx, i => WorkJob(jobs[i]));
startIdx = endIdx; endIdx = jobs.Count;
}
Oznacza to, że istnieje wiele razy, gdzie Parallel.For musi zsynchronizować. Rozważ algorytm algorytmu wykresu chleba pierwszy; liczba synchronizacji byłaby dość duża. Strata czasu, nie?
Trying to samo w podejściu staromodnym gwintowania:
var queue = new ConcurrentQueue<Job> { firstJob };
var threads = new List<Thread>();
var waitHandle = new AutoResetEvent(false);
int numBusy = 0;
for (int i = 0; i < maxThreads; i++)
threads.Add(new Thread(new ThreadStart(delegate {
while (!queue.IsEmpty || numBusy > 0) {
if (queue.IsEmpty)
// numbusy > 0 implies more data may arrive
waitHandle.WaitOne();
Job job;
if (queue.TryDequeue(out job)) {
Interlocked.Increment(ref numBusy);
WorkJob(job); // WorkJob does a waitHandle.Set() when more work was found
Interlocked.Decrement(ref numBusy);
}
}
// others are possibly waiting for us to enable more work which won't happen
waitHandle.Set();
})));
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());
Kod Parallel.For
jest oczywiście znacznie czystsze, ale czego nie mogę pojąć, to jeszcze szybciej, jak dobrze! Czy harmonogram zadań jest tak dobry? Synchronizacja została wyeliminowana, nie ma zajętego czekania, ale podejście gwintowane jest konsekwentnie wolniejsze (dla mnie). Co się dzieje? Czy podejście gwintowania może być szybsze?
Edycja: dzięki za wszystkie odpowiedzi, chciałbym móc wybrać wiele. Wybrałem ten, który pokazuje rzeczywistą możliwą poprawę.
Dlaczego miałbyś chcieć zrobić to szybciej, skoro istnieje już czystsze i szybsze rozwiązanie? – iMortalitySX
Ponieważ istnieje oczywisty niedobór, który można wyeliminować, myślę. –
Zamknij pytanie [Czy PLinq jest nieodłącznie szybszy niż System.Threading.Tasks.Parallel.ForEach] (http://stackoverflow.com/questions/5196293/is-plinq-inherentnie-faster-than-system-threading-tasks- parallel- foreach) – iMortalitySX