각 요청 항목에 대해 여러 스레드를 작성하는 방법


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-> {}} 순서 가 변경 됩니다.

예를 들면 다음과 같습니다.
Input :

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

        });

참고 : 이 작업을 수행 할 수는 있지만, parellelism과 order가 서로 잘 결혼하지 않기 때문에 성능을 면밀히 관찰해야합니다!

산출

 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를 사용하여 병렬 처리를 수행 할 수 있습니까?
mayank bisht

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하게 실행하는 대신 여기에서 사용됩니다 .


자바 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 점점 오전 : 널 (null)을
mayank을 bisht

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 개 주문 및이 규칙에 대한 유일한 유효 실행은,

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

스트리밍도 필요하지 않고 두 개의 중첩 루프 만 있습니다. 테스트 : 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-> {}} 순서가 변경됩니다.

아니 그렇지 않아. 이 order겹칠 수 있지만 각 주문의 rules 순서는 유지됩니다. 평행 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볼이야는 것을 추적 할 수 있습니다 rule들, 1-2-3로 계속오고 order . 또한 예제 목록에는 order1두 번 포함되어 있어서 무슨 일이 일어나고 있는지 알 수 없었습니다.


답변 해주셔서 감사합니다. 적은 수량의 주문에 대해서는 위의 출력이 정확할 수 있습니다. 그러나 주문을 늘리면 다른 결과가 나옵니다. 예를 들어 (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) 및 not (order1-rule1 order2-rule1 order1-rule2 order1-rule3).
mayank bisht

@mayankbisht 나는이 제한이 단순히 병렬 처리를 허용하지 않는다고 생각합니다. 업데이트 된 답변을 참조하십시오 (처음에 새로운 부분을 썼습니다).
tevemadar

예, 이해합니다. 그래서이 질문을 여기에 게시했습니다. 나는 어쩌면이 일을하는 또 다른 방법은, 아니면 우리가 너 한테이 변경됩니다 생각
bisht mayank을

@mayankbisht 당신은 왜 orders가 겹칠 수 없는지 설명 할 수 있습니다 ( rule아마도 상태가 있고 제한된 수의 사본으로 존재합니까? 아마도 하나입니까?). 그러나 일반적으로 병렬로 작동하지 않는 병렬 처리는 없습니다. 결국 병렬 처리의 요점입니다.
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.