注文レベルでマルチスレッドを使用して以下のコードを処理しようとしています。
_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
_
ordersの順序は気になりませんが、rulesの順序は気になりません。オーダーは任意の順序で処理できますが、ルールは各オーダーで同じ順序で実行する必要があります。
助けてください。
使用できます:
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
異なるスレッドから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()));
_
注:ストリームの収集中にフラットマッピングを同期的に実行するために、ここでは単純なflatMap
の代わりにCollectors.flatMapping()
を使用しています。
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());
_
これは機能しますか?
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
サードパーティのライブラリを試してもかまわない場合。これが私のライブラリのサンプルです: 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()