2013-07-25 15 views
8

Niedawno korzystałem z PLINQ, aby wykonać trochę przetwarzania danych.Dlaczego moje połączenie Parallel.ForAll kończy się przy użyciu pojedynczego wątku?

Zasadniczo mam około 4000 szeregów czasowych (więc w zasadzie instancje Dictionary<DataTime,T>), które mam na liście o nazwie timeSeries.

Aby wykonać moją pracę, ja po prostu zrobić:

timeSeries.AsParallel().ForAll(x=>myOperation(x)) 

Jeśli spojrzeć na to, co dzieje się z moimi różnych rdzeni, zauważam, że po pierwsze, wszystkie moje procesory są wykorzystywane i widzę na konsola (gdzie wysyłam niektóre logi), że kilka szeregów czasowych jest przetwarzanych w tym samym czasie.

Jednak proces jest długi i po około 45 minutach rejestracja wyraźnie wskazuje, że działa tylko jeden wątek. Dlaczego?

Próbowałem zastanowić się i zdałem sobie sprawę, że timeSeries zawiera instancje łatwiejsze do przetworzenia z punktu widzenia na początku i na końcu listy. Zastanawiałem się więc, czy być może algorytm, który wykorzystywał PLINQ, polegał na dzieleniu 4000 instancji na, powiedzmy, 4 rdzeniach, dając każdemu z nich 1000. Następnie, gdy rdzeń jest skończony z przydzielaniem pracy, wraca do stanu bezczynności. Oznaczałoby to, że jeden z rdzeń może mieć znacznie większe obciążenie pracą.

Czy moja teoria jest poprawna, czy może istnieje inne możliwe wytłumaczenie?

Czy mam przetasować listę przed uruchomieniem, czy może istnieją jakieś parametry paralelizmu, których mogę użyć, aby rozwiązać ten problem?

Odpowiedz

5

Twoja teoria jest prawdopodobnie poprawna, chociaż istnieje coś, co nazywa się "workstealing", które powinno temu zaradzić. Nie jestem pewien, dlaczego to nie działa tutaj. Czy istnieje wiele (> = dziesiątki) dużych zleceń na zewnętrznych końcach lub tylko kilku?

Oprócz przetasowania danych można użyć the overload dla AsParallel(), która akceptuje custom Partioner. To pozwoliłoby lepiej zrównoważyć pracę.

Uwaga boczna: w tej sytuacji wolałbym Parallel.ForEach(), więcej opcji i czystszą składnię.

+1

O ile mi wiadomo, kradzież działa na Zadaniach, a nie na iteracjach w PLINQ. Jeśli zadanie otrzyma kilka elementów z kolekcji do przetworzenia, inne zadania nie będą w stanie ich ukraść. – svick

+1

Również niestandardowy program do partycjonowania może nie być tutaj potrzebny, [te, które są dostarczane przez framework] (http://msdn.microsoft.com/en-us/library/system.collections.concurrent.partitioner.create.aspx) może wystarczyć. – svick

+0

@svick - prawdopodobnie masz rację, ale czy to wskazywałoby na pętlę for tworzącą grupę zadań? Wydaje się nieporęczny. –

Powiązane problemy