Czy zawsze powinienem używać strumienia równoległego, jeśli to możliwe?

W Javie 8 i lambdzie łatwo jest iterować Kolekcje jako strumienie i równie łatwo używać strumienia równoległego. Dwa przykłady z docs , drugi używając parallelStream:

myShapesCollection.stream()
    .filter(e -> e.getColor() == Color.RED)
    .forEach(e -> System.out.println(e.getName()));

myShapesCollection.parallelStream() // <-- This one uses parallel
    .filter(e -> e.getColor() == Color.RED)
    .forEach(e -> System.out.println(e.getName()));
Tak długo, jak nie zależy mi NA kolejności, Czy zawsze byłoby korzystne użycie równoległości? Można by pomyśleć, że jest to szybsze dzielenie pracy na więcej rdzeni.

Czy są inne względy? Kiedy powinien być używany strumień równoległy, a kiedy nie-równoległy używany?

(to pytanie jest zadawane, aby wywołać dyskusję o tym, jak i kiedy korzystać z równoległych strumieni, a nie dlatego, że uważam, że zawsze ich używanie jest dobrym pomysłem.)

Author: Matsemann, 2013-12-04

4 answers

Strumień równoległy ma znacznie wyższy poziom napowietrzności w porównaniu do sekwencyjnego. Koordynowanie wątków zajmuje znaczną ilość czasu. Domyślnie używałbym strumieni sekwencyjnych i rozważałbym tylko te równoległe, jeśli

  • Mam ogromną ilość przedmiotów do przetworzenia (lub przetwarzanie każdego przedmiotu zajmuje czas i jest możliwe do równoległego przetworzenia)

  • Mam problem z wydajnością

  • Nie uruchamiam jeszcze procesu w wielu wątkach środowisko (na przykład: w kontenerze internetowym, jeśli mam już wiele żądań do przetwarzania równolegle, dodanie dodatkowej warstwy równoległości wewnątrz każdego żądania może mieć bardziej negatywne niż pozytywne skutki)

W twoim przykładzie wydajność i tak będzie napędzana przez zsynchronizowany dostęp do System.out.println(), a równoległe wykonanie tego procesu nie będzie miało żadnego efektu, a nawet negatywnego.

Ponadto pamiętaj, że równoległe strumienie nie rozwiązują magicznie wszystkich problemy z synchronizacją. Jeśli współdzielony zasób jest używany przez predykaty i funkcje używane w procesie, musisz upewnić się, że wszystko jest bezpieczne dla wątków. W szczególności, skutki uboczne są rzeczy, które naprawdę trzeba się martwić, jeśli iść równolegle.

W każdym razie mierz, nie zgaduj! Tylko pomiar powie Ci, czy równoległość jest tego warta, czy nie.
 500
Author: JB Nizet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-10 03:07:16

Stream API został zaprojektowany, aby ułatwić pisanie obliczeń w sposób abstrakcyjny od sposobu ich wykonywania, dzięki czemu przełączanie między sekwencyjnym i równoległym jest łatwe.

Jednak tylko dlatego, że jest to łatwe, nie oznacza, że zawsze jest to dobry pomysł, a w rzeczywistości jest tozły pomysł, aby po prostu upuścić .parallel() wszędzie, po prostu dlatego, że możesz.

Po pierwsze, zauważ, że równoległość nie oferuje żadnych korzyści innych niż możliwość szybszego wykonania, gdy więcej dostępne są rdzenie. Równoległe wykonanie zawsze będzie wymagało więcej pracy niż sekwencyjnej, ponieważ oprócz rozwiązania problemu, musi również wykonywać dyspozytornię i koordynację zadań podrzędnych. Nadzieja jest taka, że będziesz w stanie szybciej dotrzeć do odpowiedzi, dzieląc pracę na wiele procesorów; to, czy tak się dzieje, zależy od wielu rzeczy, w tym od wielkości zestawu danych, ile obliczeń robisz na każdym elemencie, charakteru obliczeń (w szczególności, czy przetwarzanie jednego elementu wchodzi w interakcje z przetwarzaniem innych?), liczbę dostępnych procesorów oraz liczbę innych zadań konkurujących o te procesory.

Ponadto należy zauważyć, że paralelizm często ujawnia nieeterminizm w obliczeniach, który jest często ukryty przez sekwencyjne implementacje; czasami nie ma to znaczenia lub może być złagodzone przez ograniczenie zaangażowanych operacji (np. operatory redukcji muszą być bezpaństwowe i asocjacyjne.)

W rzeczywistości, czasami paralelizm przyspieszy twoje obliczenia, czasami nie, a czasami nawet spowolni. Najlepiej jest rozwinąć najpierw przy użyciu sekwencyjnego wykonywania, a następnie zastosować równoległość, gdzie (a) wiesz, że rzeczywiście istnieje korzyść dla zwiększonej wydajności i (B) że faktycznie zapewni ona zwiększoną wydajność. A) jest problemem biznesowym, a nie technicznym. Jeśli jesteś ekspertem od wydajności, zazwyczaj będziesz mógł spojrzeć na kod i określić (B), ale inteligentna ścieżka jest do pomiaru. (I nawet nie kłopocz się, dopóki nie przekonasz się (A); jeśli kod jest wystarczająco szybki, lepiej zastosować swoje cykle mózgu gdzie indziej.)

Najprostszym modelem wydajności dla równoległości jest model" NQ", gdzie N to liczba elementów, A Q to obliczenia na element. Ogólnie rzecz biorąc, produkt NQ musi przekroczyć pewien próg, zanim zaczniesz uzyskiwać korzyści z wydajności. Dla problemu low-Q, takiego jak " Dodaj liczby od 1 do N", na ogół obserwuje się przerwę między N = 1000 A N = 10000. W przypadku problemów z wyższym-Q, zobaczysz przerwy w niższych progach.

Ale rzeczywistość jest dość skomplikowana. Więc dopóki nie osiągniesz doświadczenia, najpierw zidentyfikuj, kiedy przetwarzanie sekwencyjne faktycznie kosztuje coś, a następnie zmierz, czy równoległość pomoże.
 176
Author: Brian Goetz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-24 16:45:43

Oglądałem jedną z prezentacji Briana Goetza (Java Language Architect & specification lead for Lambda Expressions) . Wyjaśnia on szczegółowo następujące 4 punkty do rozważenia przed przejściem do równoległości: {]}

Koszty podziału / rozkładu
- Czasami dzielenie jest droższe niż tylko praca!
koszty wysyłki / zarządzania zadaniami
- Może wykonać wiele pracy w czasie potrzebnym do ręcznej pracy do innego nić.
Koszt połączenia wyniku
- Czasami połączenie wymaga kopiowania dużej ilości danych. Na przykład dodawanie liczb jest tanie, podczas gdy łączenie zestawów jest drogie.
miejscowość
- Słoń w pokoju. Jest to ważny punkt, który każdy może przegapić. Powinieneś rozważyć chybienia pamięci podręcznej, jeśli procesor czeka na dane z powodu chybień pamięci podręcznej, to nie zyskasz nic przez równoległość. Dlatego źródła oparte na tablicach najlepiej porównują się z kolejnymi indeksami (w pobliżu bieżącego indeksu) są buforowane i istnieje mniejsza szansa, że procesor doświadczy braku pamięci podręcznej.

Wspomina również o stosunkowo prostym wzorze do określenia szansy równoległego przyspieszenia.

Model NQ :

N x Q > 10000

gdzie,
N = liczba pozycji danych
Q = ilość pracy na przedmiot

 40
Author: Ram Patra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-21 17:40:37

JB uderzył w gwoździe w głowę. Jedyne, co mogę dodać, to to, że Java8 nie wykonuje czystego przetwarzania równoległego, robi paraquential Tak napisałem artykuł i robię F / J przez trzydzieści lat, więc rozumiem problem.

 11
Author: edharned,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-04 19:39:33