Java8 i parallelStream

Java8 i parallelStream
shagrin
  • Rejestracja:około 17 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Norwegia, Stavanger
0

Hej,

Przerobiłam sobie jakieś materiały o java8, w tym tez jakaś książkę. W książce były przedstawione parallelStream'y i nawet zachwalali, żeby ich używać.

Na różnych forach jest to jednak odradzane, bo może skutkować tgread starvation.

Jakie macie opinie w tym temacie na podstawie posiadanego doświadczenia? Czy parallelStream faktycznie powinien być zupełnie zbanowany, czy można go używać przy pewnych założeniach?


Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Paralell stream należy używać rozumiejąc ja on działa. Konkretnie rozumiejąc że bierze domyślny fork-join pool! Więc jeśli wrzucisz tam coś dużego do przetwarzania to możesz powiesić aplikacje, bo wszystkie wątki będą mielić.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
0

Ogolnie to pamietam, ze byly kiedys jakies problemy ale z tego co pamiętam zostal fixniete. Teraz trzeba uzywac z rozwaga po prostu.

shagrin
  • Rejestracja:około 17 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Norwegia, Stavanger
0

To wszystko jest jasne, ale nie bardzo rozumiem, gdzie w takim razie jest sens?


Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 3 godziny
0
Shalom napisał(a):

Paralell stream należy używać rozumiejąc ja on działa. Konkretnie rozumiejąc że bierze domyślny fork-join pool! Więc jeśli wrzucisz tam coś dużego do przetwarzania to możesz powiesić aplikacje, bo wszystkie wątki będą mielić.

Mógłbyś rozwinąć? Fork join pool to pula wątków odseparowana od np głównego wątku, Event Dispatch Thread, wątków GC czy masy innych wątków. System operacyjny przełącza się między wątkami nawet jeżeli jest ich więcej niż rdzeni procesora (w praktyce jednocześnie działających wątków w systemie jest o rzędy wielkości więcej niż logicznych rdzeni).

Blokowanie puli wątków jest generalnie niezwiązane z Parallel Streams z Javy. Jeśli zrobię sobie Executors.newFixedThreadPool(5) i wrzucą tam 5 Runnable, które sobie śpią przez 10 lat to właśnie przyblokowałem pulę wątków na te 10 lat. Parallel Streams nie jest jedyną abstrakcją korzystającą z pul wątków - praktycznie wszystkie abstrakcje na równoległe wykonywanie zadań korzystają z pul wątków (włączając w to Future, async/ await i inne wynalazki).

Wadą Parallel Streams w obecnej implementacji (Java 8) jest to, że nie da się podać innej puli wątków niż domyślna (i wspólna dla wszystkich wywołań Parallel Streams), a domyśla pula ma stały rozmiar (ZTCW równy ilości logicznych rdzeni). Z tego względu najlepiej jest unikać używania Parallel Streams w przypadku zadań, gdzie trzeba czekać na dane wejściowe, czyli np wczytywania danych z sieci czy bazy danych. W takich przypadkach lepiej użyć np CompletableFuture.

Z drugiej strony istnieje coś takiego jak ForkJoinPool.ManagedBlocker i to ma sprawić, że potencjalnie zostanie stworzony ekstra wątek dla blokującego wywołania. Jak to działa to nie sprawdzałem.

PS:
W Javce już dawno nie programuję, więc możliwe, że niektóre rzeczy działają inaczej niż sobie wyobrażam.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

Sens jest wtedy gdy operacje trwają długo, np. ja bym użył do kopiowania plików. Chociaż po tym co napisał @Shalom nie jestem pewien


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
edytowany 1x, ostatnio: scibi92
shagrin
  • Rejestracja:około 17 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Norwegia, Stavanger
0
scibi92 napisał(a):

Sens jest wtedy gdy operacje trwają długo, np. ja bym użył do kopiowania plików. Chociaż po tym co napisał @Shalom nie jestem pewien

No właśnie przy długotrwałych operacjach można ubić system podobno


Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 3 godziny
0

podobno

W jaki sposób? Może zamiast bawić się w głuchy telefon w końcu ktoś zademonstruje problem?


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
shagrin
  • Rejestracja:około 17 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Norwegia, Stavanger
0

Chociazby przykład z tego artykułu: https://dzone.com/articles/think-twice-using-java-8


S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

A racja, już wiem o co chodzi ;) Tak rzeczywiście, wątek będzie czekał na zakończenie parrarel stream i dlatego jeśli coś dłużej trwa to jest "zamrożony" wątek z ktorego poszedł ten stream ;)
Edit: chociaż to i tak w sumie jest lepiej jakby wtedy był użyty "normalny" stream, bo też by zamroził wątek z którego poszedł tylko na dłużej ;)


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
edytowany 1x, ostatnio: scibi92
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 3 godziny
0

@shagrin:
Napisz mi gdzie tam jest napisane coś o "ubijaniu systemu" i co to w ogóle znaczy?

W artykule jest napisane tylko, że jedne zadania mogą blokować inne i trzeba mieć to na uwadze. ForkJoinPool jest dość niedeterministyczny jeśli chodzi o kolejność wykonywania zadań ponieważ implementuje work stealing, ale niedeterminizm i tak jest czymś powszednim podczas programowania równoległego. Słusznie wskazano, że Parallel Streams w Javie 8 nie dają możliwości wyboru puli wątków.

...ale to opisałem już w poprzednim poście. Moim zdaniem kuleje u ciebie czytanie ze zrozumieniem.

Edit: chociaż to i tak w sumie jest lepiej jakby wtedy był użyty "normalny" stream, bo też by zamroził wątek z którego poszedł tylko na dłużej ;)

No właśnie! Jeśli gdzieś tam mam Thread.sleep(10 lat) to jakiś wątek zostanie zablokowany na 10 lat. Proste i logiczne. Wrzucenie Thread.sleep(10 lat) do wątku z domyślnej puli ForkJoinPool nie sprawi magicznie, że system wybuchnie. Po prostu inny wątek zostanie zablokowany niż przy braku użycia Parallel Streams.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Tak jak napisał @Wibowit a wcześniej pisałem ja, paralell stream używa domyślnego fork join pool, więc jeśli załadujemy tam wykonanie czegoś co jest długie (np. przetworzenie n elementów z których każdy sie blokuje przy przetwarzaniu, a mamy n rdzeni) to cokolwiek innego korzystającego z tego samego fork join pool musi wisieć i czekać aż się coś zwolni.
Zasada jest podobna jak wykonywanie długich operacji w wątku GUI -> nie należy tego robić bo interfejs wisi.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
TD
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 4 lata
  • Postów:380
0
Shalom napisał(a):

to cokolwiek innego korzystającego z tego samego fork join pool musi wisieć i czekać aż się coś zwolni.

A co innego może korzystać z tego samego fork join pool?

Zobacz pozostałe 4 komentarze
Wibowit
Moim zdaniem ta wspólna pula to java.util.concurrent.ForkJoinPool#commonPool
airborn
@Wibowit: to to na pewno. Pytanie gdzie w kodzie siedzi że to commonPool, albo inny pool o którym piszę niżej. Tego nie wiem i niechce mi się szukać. @tdudzik nie rozumiem pytania. Co dokładnie wiem jak działa? Skąd wiem, że paralleStream wykorzystuje ForkJoinFramework? Chociażby z tego taska o którym pisałem przed chwilą.
TD
Skąd wiesz, że parallelStream wykorzystuje jeden wspólny fork join pool, przez co zablokowanie n wątków, gdzie n to ilość rdzeni spowoduje zablokowanie innych parallelStreamów
Wibowit
Jest sobie metoda java.util.concurrent.ForkJoinTask#fork która wykorzystuje ten commonPool, no chyba że zastosowany jest 'hack' z posta poniżej. Z implementacji metody fork widać też wprost czemu ten hack działa.
TD
ok, w takim razie przejrzę kod ForkJoinTask i metod o których mówicie, dzięki. ;)
airborn
  • Rejestracja:prawie 16 lat
  • Ostatnio:prawie 7 lat
  • Postów:274
2

Tak jak koledzy wspomnieli, domyślnie wykorzystywana jest domyślna pula z ForkJoinPool ALE jest też metoda żeby to zmienić. Traktował bym to trochę bardziej jako hack, no ale cóż:

Kopiuj
ForkJoinPool forkJoinPool = new ForkJoinPool(2);
forkJoinPool.submit(() ->
    //parallel task here, for example
    IntStream.range(1, 1_000_000).parallel().filter(PrimesPrint::isPrime).collect(toList())
).get();

Można streama wykonać w innej puli i wówczas wykorzysta on tę pulę do pracy

Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 3 godziny
0

Niby wygląda jak hack, ale by użyć niedomyślnej puli wątków w przypadku async/ await w C# trzeba zrobić coś dość podobnego:
https://stackoverflow.com/a/23959475

Kopiuj
var prevCtx = SynchronizationContext.Current; 
try 
{
    SynchronizationContext.SetSynchronizationContext(new ThreadPoolSynchronizationContext()); 

    // async operations.
} 
finally 
{  
    SynchronizationContext.SetSynchronizationContext(prevCtx); 
} 

Wygląda to nawet bardziej imperatywnie od tego hacka w Javie.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.