Her istek öğesi için birden çok iş parçacığı oluşturma


9

Sipariş düzeyinde multithreading kullanarak aşağıdaki kodu işlemeye çalışıyorum.

List<String> orders = Arrays.asList("order1", "order2", 
                   "order3", "order4", "order1");

Geçerli sıralı yürütme:

orders.stream().forEach(order -> {
    rules.forEach(rule -> {
        finalList.add(beanMapper.getBean(rule)
                .applyRule(createTemplate.apply(getMetaData.apply(rule), command),
                           order));
    });
});

Kullanmayı denedim:

orders.parallelStream().forEach(order -> {}} // code snippet.

Ancak rules.forEach (kural -> {}} sırasını değiştiriyor.

Örneğin:
Giriş:

 List<String> orders = Arrays.asList("order1", "order2", 
                         "order3", "order4", "order1");
 List<String> rules = Arrays.asList("rule1", "rule2", "rule3");

Beklenen çıktı:

order1 with rule1, rule2, rule3
order2 with rule1, rule2, rule3

Gerçek çıktı parallelStream():

order1 with rule3, rule1, rule2
order1 with rule2, rule1, rule3

Ben emirlerin sırası hakkında rahatsız değil , ama kuralların eh sipariş hakkında rahatsız . Siparişler herhangi bir sırada işlenebilir, ancak kurallar her sipariş için aynı sırada yürütülmelidir.

Lütfen yardım et.

Yanıtlar:


4

Kullanabilirsiniz :

orders.stream().parallel().forEachOrdered(// Your rules logic goes here. )

ForEachOrdered, Akış sırasının korunmasını garanti eder.

Yani referans için:

orders.stream().parallel().forEachOrdered( order -> {

            rules.stream().parallel().forEachOrdered ( rule -> {

                 System.out.println( " Order : " + order + " rule :" + rule);
            });

        });

Not: Bunu yapabilmemize rağmen, performans yakından izlenmelidir çünkü parelizm ve düzen birbiriyle çok iyi evlenmez!

Çıktı

 Order : order1 rule :rule1
 Order : order1 rule :rule2
 Order : order1 rule :rule3
 Order : order2 rule :rule1
 Order : order2 rule :rule2
 Order : order2 rule :rule3
 Order : order3 rule :rule1
 Order : order3 rule :rule2
 Order : order3 rule :rule3
 Order : order4 rule :rule1
 Order : order4 rule :rule2
 Order : order4 rule :rule3
 Order : order1 rule :rule1
 Order : order1 rule :rule2
 Order : order1 rule :rule3

Cevap için teşekkürler. forEachOrdered akış sırasını garanti eder, ancak daha sonra performansı yavaşlatır. Ben denedim ve uygulama sıralı işleme benzer zaman alıyor. paralel ve forEachOrdered birbirlerine iltifat etmez.
mayank bisht

Evet, bunu yapmadan önce tam gecikme analizi yapmamız gerektiğine katılıyorum.
Pramod S.Nikam

Evet, bunu kullanarak aynı performansı alıyorum, gelişme yok.
mayank bisht

1
Bunu yapmak için daha iyi bir çözüm elde etmek için bu konuyu yakından takip edin.
Pramod S.Nikam

ExecutorService kullanarak paralel işleme yapabilir miyim?
mayank bisht

1

finalListFarklı iş parçacıklarına aynı anda öğe eklersiniz . Bu, kuralların farklı siparişlere uygulanmasının sonuçlarının karıştırılmasına neden olur (kurallar siparişlerine göre gruplandırılmaz).

Her biri için geçici bir liste oluşturarak orderve ardından a'daki tüm geçici listeleri senkronize olarak birleştirerek düzeltebilirsiniz finalList.

Stream-API (Java 9+) kullanarak bunu nasıl yapabileceğiniz aşağıda açıklanmıştır:

List<AppliedRule> finalList = orders.parallelStream().map(order ->
        rules.stream().map(rule -> applyRule(order, rule)).collect(Collectors.toList())
).collect(Collectors.flatMapping(Collection::stream, Collectors.toList()));

Not: Collectors.flatMapping()Burada, flatMapakış toplama sırasında düz eşlemeyi eşzamanlı olarak çalıştırmak için basit yerine kullanılır .


Java 8 analogu:

List<AppliedRule> finalList = orders.parallelStream().map(order ->
        rules.stream().map(rule -> applyRule(order, rule)).collect(Collectors.toList())
).collect(Collectors.toList())
        .stream()
        .flatMap(Collection::stream)
        .collect(Collectors.toList());

Cevap için teşekkürler. Yaklaşımınızı denedim ve java.util.ConcurrentModificationException alıyorum: null
mayank bisht

finalList = orders.parallelStream () .map (sipariş -> rules.stream () .map (kural -> beanMapper.getBean (kural) .applyRule (createTemplate.apply (getMetaData.apply (kural), komut), sipariş)) .Yaðlar (Collectors.toList ())) toplamak (Collectors.toList ()) akışı () flatMap (Koleksiyon :: stream) .Yaðlar (Collectors.toList (.))..;
Maya Bisht

@mayankbisht, bu beanMapper.getBean(rule) .applyRule(createTemplate.apply(getMetaData.apply(rule), command), order)saf bir işlev olmadığı anlamına gelir, bu yüzden paralel olarak kullanılamaz. Ondan tüm yan etkileri kaldırmaya çalışın; ConcurrentModificationExceptionyığın izleme onları bulmak için yardımcı olabilir.
Bananon

0

Bu işe yarayacak mı?

final int rulesSize = rules.size();
AtomicInteger atomicInteger = new AtomicInteger(0);
orders.stream().parallel().forEach(order -> {
    IntStream.range(0, rulesSize).parallel().forEach( i -> {
        synchronized (atomicInteger) {
            System.out.println(" Order : " + order + " rule :" + rules.get(atomicInteger.getAndIncrement() % rulesSize));
        }
    });
});

Çıktı

 Order : order1 rule :rule1
 Order : order4 rule :rule2
 Order : order1 rule :rule3
 Order : order3 rule :rule1
 Order : order3 rule :rule2
 Order : order3 rule :rule3
 Order : order2 rule :rule1
 Order : order2 rule :rule2
 Order : order2 rule :rule3
 Order : order1 rule :rule1
 Order : order1 rule :rule2
 Order : order4 rule :rule3
 Order : order1 rule :rule1
 Order : order4 rule :rule2
 Order : order1 rule :rule3

0

Emirlerin sırası herhangi bir şey olabilir, ancak kuralların sırası değişmemelidir. Ayrıca belirli bir düzen için kural bir grup halinde gelmelidir.

Durum buysa, gerçek paralelliğe yer yoktur.

Ne zaman

order1-rule1
order1-rule2
order2-rule1
order2-rule2

ve

order2-rule1
order2-rule2
order1-rule1
order1-rule2

2 sipariş ve 2 kural için geçerli olan tek işlemdir
ve

order1-rule1
order2-rule1
order1-rule2
order2-rule2

geçersiz kabul edilir, bu paralellik değildir, sadece orders'nin rastgele elde edilmesi , muhtemelen kazanç olmadan. Her zaman order1ilk gelen "sıkılmış" iseniz, listeyi karıştırabilirsiniz, ama hepsi bu:

public static void main (String[] args) throws java.lang.Exception
{
    List<String> orders = Arrays.asList("order1", "order2", "order3", "order4");
    List<String> rules = Arrays.asList("rule1", "rule2", "rule3");
    Collections.shuffle(orders);
    orders.forEach(order->{
        rules.forEach(rule->{
            System.out.println(order+"-"+rule);
        });
    });
}

Akış bile gerekmez, sadece iki iç içe döngü. Test: https://ideone.com/qI3dqd

order2-rule1
order2-rule2
order2-rule3
order4-rule1
order4-rule2
order4-rule3
order1-rule1
order1-rule2
order1-rule3
order3-rule1
order3-rule2
order3-rule3


Orijinal cevap

Ancak rules.forEach (kural -> {}} sırasını değiştiriyor.

Hayır. orderS çakışabilir, fakat sırası ruleher bir sipariş için s tutulur. Neden paralel forEacholmayan başka bir şey yapsın ki?

Örnek kod:

public static void main (String[] args) throws java.lang.Exception
{
    List<String> orders = Arrays.asList("order1", "order2", "order3", "order4");
    List<String> rules = Arrays.asList("rule1", "rule2", "rule3");
    orders.stream().parallel().forEach(order->{
        rules.forEach(rule->{
            System.out.println(order+"-"+rule);
        });
    });
}

Test: https://ideone.com/95Cybg
Örnek çıktı:

order2-rule1
order2-rule2
order2-rule3
order1-rule1
order1-rule2
order1-rule3
order4-rule1
order4-rule2
order4-rule3
order3-rule1
order3-rule2
order3-rule3

orderS sırası karıştırılır, ancak rules daima 1-2-3'tür. Bence çıktılarınız sadece eşleştirmeleri sakladı (aslında nasıl üretildiğini göstermediniz).

Tabii ki bazı gecikmelerle uzatılabilir, bu nedenle orders'nin işlenmesi aslında örtüşecektir:

public static void delay(){
    try{
        Thread.sleep(ThreadLocalRandom.current().nextInt(100,300));
    }catch(Exception ex){}
}

public static void main (String[] args) throws java.lang.Exception
{
    List<String> orders = Arrays.asList("order1", "order2", "order3", "order4");
    List<String> rules = Arrays.asList("rule1", "rule2", "rule3");
    orders.stream().parallel().forEach(order->{
        rules.forEach(rule->{
            delay();
            System.out.println(order+"-"+rule);
        });
    });
}

Test: https://ideone.com/cSFaqS
Örnek çıktı:

order3-rule1
order2-rule1
order2-rule2
order3-rule2
order3-rule3
order2-rule3
order1-rule1
order4-rule1
order1-rule2
order4-rule2
order4-rule3
order1-rule3

Bu, sadece orderxparçası olmadan gördüğünüz bir şey olabilir . İle ordergörünebilir durumda o izlenebilir ruleler, 1-2-3 gelmeye devam başınaorder . Ayrıca, örnek listeniz order1iki kez içeriyordu ve kesin olarak ne olduğunu görmenize yardımcı olmadı.


Cevap için teşekkürler. Yukarıdaki çıktı daha az sayıda sipariş için doğru olabilir. Ancak siparişleri arttırırsanız, farklı bir çıktı alırsınız. Örneğin (sipariş4-kural1 sipariş4-kural2 sipariş4-kural1) (sipariş1-kural1 sipariş1-kural2) (sipariş3-kural1 sipariş3-kural2) (sipariş4-kural1 sipariş4-kural2 sipariş4-kural1 sipariş4-kural2).
Maya bisht

Emirlerin sırası herhangi bir şey olabilir, ancak kuralların sırası değişmemelidir. Ayrıca belirli bir düzen için kural bir grup halinde gelmelidir. Örn. (sipariş1-kural 1 sipariş1-kural2 sipariş1-kural3) ve değil (sipariş1-kural1 sipariş2-kural1 sipariş1-kural2 sipariş1-kural3).)
mayank bisht

@mayankbisht Bu kısıtlamaların paralel işlemeye izin vermediğini düşünüyorum. Güncellenmiş cevaba bakın (başlangıçta yeni kısmı yazdım).
tevemadar

Evet, bunu anlıyorum ve bu yüzden bu soruyu buraya gönderdim. Belki bunu yapmanın başka bir yolu olacağını düşündüm, ya da belki algo
mayank bisht'i

@mayankbisht s'nin neden orderüst üste binemediğini açıklayabilirsiniz ( rulebelki de durum bilgisi olan ve sınırlı sayıda kopyada, belki de yalnızca bir tanesinde var olan). Ancak genellikle paralel koşan şeylerin olmadığı bir paralellik yoktur, sonuçta paralelliğin bütün noktası budur.
tevemadar

0

Üçüncü taraf kitaplığını denemeyi düşünmüyorsanız. İşte kütüphanemle örnek: abacus-util

StreamEx.of(orders).parallelStream().forEach(order -> {}}

Ve hatta iplik numarasını belirtebilirsiniz:

StreamEx.of(orders).parallelStream(maxThreadNum).forEach(order -> {}}

Sırası rulekorunacaktır.

Bu arada, paralel akışta olduğundan, kod parçası ...finalList.add(...büyük olasılıkla çalışmaz. Sonuçları listelemek için daha iyi olduğunu düşünüyorum:

StreamEx.of(orders).parallelStream().map/flatMap(order -> {...}}.toList()

orderdaha sonra bir nedenden dolayı sırasını korumak isteseniz bile yapılabilir :

StreamEx.of(orders).indexed().parallelStream()
      .map/flatMap(order -> {...}}.sortedBy(...index).toList()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.