リクエストアイテムごとに複数のスレッドを作成する方法


9

注文レベルでマルチスレッドを使用して以下のコードを処理しようとしています。

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

現在の順次実行:

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

私は使ってみました:

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

しかし、rules.forEach(rule-> {}}の順序を変更しています。

例:
入力:

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

期待される出力:

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

実際の出力parallelStream()

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

注文の順番は気になりませんが、ルールの順番は気になりません。オーダーは任意の順序で処理できますが、ルールは各オーダーで同じ順序で実行する必要があります。

助けてください。

回答:


4

使用できます:

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

ForEachOrderedは、ストリームの順序を維持することを保証します。

参考までに:

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

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

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

        });

注:これは可能ですが、並列性と秩序は互いにうまく調和しないため、パフォーマンスを注意深く監視する必要があります!

出力

 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

答えてくれてありがとう。forEachOrderedはストリームの順序を保証しますが、パフォーマンスも低下します。試してみましたが、アプリケーションはシーケンシャル処理と同様に時間がかかります。stream()。parallel&forEachOrderedは互いに補完し合いません。
Mayank bisht

そうですね、これを行う前に完全なレイテンシ分析を行う必要があることに同意します。
Pramod S. Nikam

うん、私はこれを使用して同じパフォーマンスを得ていますが、改善はありません。
Mayank bisht

1
これを行うためのより良い解決策を得るために、このスレッドを厳密にフォローします。
Pramod S. Nikam

ExecutorServiceを使用して並列処理を実現できますか?
bisht mayank

1

finalList異なるスレッドのに同時に要素を追加します。これにより、さまざまな注文にルールを適用した結果が混在します(ルールは注文によってグループ化されていません)。

それぞれの一時リストを作成してから、のorderすべての一時リストを同期的にマージすることで修正できますfinalList

Stream-API(Java 9+)を使用してそれを行う方法は次のとおりです。

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

注:Collectors.flatMapping()ここでは、flatMapストリームコレクション中にフラットマッピングを同期的に実行するのではなく、ここで使用します。


Java 8アナログ:

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());

答えてくれてありがとう。私はあなたのアプローチを試してみました&Iはjava.util.ConcurrentModificationExceptionが取得しています:ヌル
bisht mayank

finalList = orders.parallelStream().map(order-> rules.stream().map(rule-> beanMapper.getBean(rule).applyRule(createTemplate.apply(getMetaData.apply(rule)、command)、order)) .collect(Collectors.toList()))。collect(Collectors.toList())。stream()。flatMap(Collection :: stream).collect(Collectors.toList());
Mayank bisht

@mayankbisht、これはこれbeanMapper.getBean(rule) .applyRule(createTemplate.apply(getMetaData.apply(rule), command), order)が純粋な関数ではないため、並行して使用できないことを意味します。そこからすべての副作用を取り除くようにしてください。ConcurrentModificationExceptionスタックトレースはそれらを見つけるのに役立ちます。
Bananon

0

これは機能しますか?

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));
        }
    });
});

出力

 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

順序は何でもかまいませんが、ルールの順序は変更しないでください。また、特定の注文ルールはグループに入れるべきです。

その場合、実際の並列処理の余地はありません。

いつ

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

そして

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

2つのオーダーと2つのルールの唯一の有効な実行で
あり、

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

は無効と見なされます。これは並列処理ではなく、ordersのランダム化であり、おそらくゲインなしです。order1常に最初に来ることに「退屈」している場合は、リストをシャッフルできますが、それだけです。

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);
        });
    });
}

ストリーミングも必要ありません。入れ子になった2つのループだけです。テスト: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


元の答え

しかし、rules.forEach(rule-> {}}の順序を変更しています。

いいえ、違います。ordersが重複してもよいが、順rule各注文のSが保持されます。非パラレルforEachが他に何をするのですか?

コード例:

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);
        });
    });
}

テスト:https : //ideone.com/95Cybg
出力例:

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 の順序は混在していますが、rulesは常に1-2-3です。私はあなたの出力がペアリングを単に隠したと思います(実際には、それがどのように生成されたかを示していませんでした)

もちろん、それをいくつかの遅延で拡張することができるので、ordersの処理は実際にオーバーラップします:

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);
        });
    });
}

テスト:https : //ideone.com/cSFaqS
出力例:

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

これは、orderx一部を除いて、あなたが見たものかもしれません。order追跡することができ、可視だrulesは、1-2-3のようにくるごとorder。また、サンプルリストにはorder12度含まれていますが、何が起こっているのかを確認するのに役立ちませんでした。


答えてくれてありがとう。上記の出力は、注文数が少ない場合は正しい場合があります。ただし、次数を増やすと、異なる出力が得られます。例:(order4-rule1 order4-rule2 order4-rule1)(order1-rule1 order1-rule2)(order3-rule1 order3-rule2)(order4-rule1 order4-rule2 order4-rule1 order4-rule2)
Mayank bisht

順序は何でもかまいませんが、ルールの順序は変更しないでください。また、特定の注文ルールはグループに含まれる必要があります。例のために。(order1- rule 1 order1-rule2 order1-rule3)ではなく(order1-rule1 order2-rule1 order1-rule2 order1-rule3)ではありません。)
Mayank bisht

@mayankbishtこれらの制限は並列処理を許可しないと思います。更新された回答を参照してください(最初に新しい部分を書きました)。
tevemadar

うん、私はそれを理解しています。それが私がこの質問をここに投稿した理由です。私は多分これを行うための別の方法があります、または多分私達はアルゴを変えることができると思った
bisht mayank

@mayankbisht ordersが重複できない理由を説明できます(これらruleのsはおそらくステートフルであり、限られた数のコピーに存在し、おそらく1つだけですか?)。しかし、一般に、並列処理がなければ並列処理はありません。結局のところ、それが並列処理の要点です。
tevemadar

0

サードパーティのライブラリを試してもかまわない場合。これが私のライブラリのサンプルです:abacus-util

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

また、スレッド番号を指定することもできます。

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

の順序はrule保持されます。

ちなみに、並列ストリームであるため、...finalList.add(...ほとんどのコードは機能しません。リストに結果を集めた方が良いと思います:

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

order後でなんらかの理由での順序を維持したい場合でも実行できます。

StreamEx.of(orders).indexed().parallelStream()
      .map/flatMap(order -> {...}}.sortedBy(...index).toList()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.