Próbuję przetworzyć poniższy kod przy użyciu wielowątkowości na poziomie zamówienia.
List<String> orders = Arrays.asList("order1", "order2",
"order3", "order4", "order1");
Bieżące wykonywanie sekwencyjne:
orders.stream().forEach(order -> {
rules.forEach(rule -> {
finalList.add(beanMapper.getBean(rule)
.applyRule(createTemplate.apply(getMetaData.apply(rule), command),
order));
});
});
Próbowałem użyć:
orders.parallelStream().forEach(order -> {}} // code snippet.
Ale zmienia reguły. Dla każdego (zasada -> {}} kolejność.
Na przykład:
Input:
List<String> orders = Arrays.asList("order1", "order2",
"order3", "order4", "order1");
List<String> rules = Arrays.asList("rule1", "rule2", "rule3");
Oczekiwany wynik:
order1 with rule1, rule2, rule3
order2 with rule1, rule2, rule3
Rzeczywista wydajność przy parallelStream()
:
order1 with rule3, rule1, rule2
order1 with rule2, rule1, rule3
Nie przejmuję się kolejnością zamówień , ale niepokoi mnie kolejność reguł . Zamówienia mogą być przetwarzane w dowolnej kolejności, ale reguły powinny być wykonywane w tej samej kolejności dla każdego zamówienia.
Proszę pomóż.
java
multithreading
java-8
java-stream
mayank bisht
źródło
źródło
W
finalList
tym samym czasie dodajesz elementy z różnych wątków. Powoduje to mieszanie wyników stosowania reguł do różnych zamówień (reguły nie są grupowane według ich zamówień).Możesz to naprawić, tworząc listę tymczasową dla każdej,
order
a następnie synchronicznie łącząc wszystkie listy tymczasowe w plikufinalList
.Oto, jak możesz to zrobić za pomocą Stream-API (Java 9+):
Uwaga:
Collectors.flatMapping()
jest tu stosowane zamiast prostegoflatMap
synchronizowania płaskiego mapowania podczas zbierania strumienia.Java 8 analogowy:
źródło
beanMapper.getBean(rule) .applyRule(createTemplate.apply(getMetaData.apply(rule), command), order)
nie jest to czysta funkcja, więc nie można jej używać równolegle. Spróbuj usunąć z niego wszystkie skutki uboczne;ConcurrentModificationException
śledzenie stosu może pomóc w ich zlokalizowaniu.Czy to zadziała?
Wynik
źródło
W takim przypadku nie ma miejsca na faktyczną równoległość.
Kiedy
i
są jedynymi prawidłowymi przebiegami dla 2 zamówień i 2 reguł,
oraz
jest uważany za nieważny, to nie jest paralelizm, tylko randomizacja
order
s, prawdopodobnie bez wzmocnienia. Jeśli „nudzi cię” ciągłeorder1
zajmowanie pierwszego miejsca, możesz przetasować listę, ale to wszystko:Nawet transmisja strumieniowa nie jest konieczna, tylko dwie zagnieżdżone pętle. Test: https://ideone.com/qI3dqd
Oryginalna odpowiedź
Nie. W
order
y mogą zachodzić na siebie, a kolejnośćrule
S dla każdego rzędu są przechowywane. Dlaczego nierównoległość miałabyforEach
robić cokolwiek innego?Przykładowy kod:
Test: https://ideone.com/95Cybg
Przykładowy wynik:
Kolejność
order
s jest mieszana, alerule
s są zawsze 1-2-3. Myślę, że twój wynik po prostu ukrył pary (w rzeczywistości nie pokazałeś, jak został wygenerowany).Oczywiście można go rozszerzyć z pewnymi opóźnieniami, więc przetwarzanie
order
s faktycznie się nakłada:Test: https://ideone.com/cSFaqS
Przykładowy wynik:
To może być coś, co widziałeś, tylko bez tej
orderx
części. Zorder
widocznymi s można śledzić, żerule
ciągle pojawiają się jako 1-2-3, naorder
. Ponadto twoja przykładowa lista zawierałaorder1
dwa razy, co z pewnością nie pomogło zobaczyć, co się dzieje.źródło
order
s nie może się nakładać (rule
być może są one stanowe i istnieją w ograniczonej liczbie kopii, być może tylko w jednym?). Ale generalnie nie ma paralelizmu bez rzeczy biegnących równolegle, to przecież cały punkt równoległości.Jeśli nie masz nic przeciwko wypróbowaniu biblioteki innej firmy. Oto przykład z moją biblioteką: abacus-util
Możesz nawet podać numer wątku:
Kolejność
rule
zostanie zachowana.Nawiasem mówiąc, ponieważ jest to strumień równoległy, fragment kodu
...finalList.add(...
najprawdopodobniej nie zadziała. Myślę, że lepiej jest zebrać wynik na liście:jest to również wykonalne, nawet jeśli z
order
jakiegoś powodu chcesz zachować kolejność :źródło