วิธีสร้างหลายเธรดสำหรับแต่ละรายการที่ร้องขอ


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.

แต่มันกำลังเปลี่ยนกฎสำหรับคำสั่งforEach (กฎ -> {}}

ตัวอย่างเช่น:
อินพุต:

 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 : 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 รับประกันลำดับของการสตรีม แต่ก็ทำให้ประสิทธิภาพช้าลง ฉันลองแล้ว & แอปพลิเคชันใช้เวลาคล้ายกับการประมวลผลตามลำดับ สตรีม (). ขนาน & forEachOrdered ไม่ได้ชื่นชมซึ่งกันและกัน
mayank

ใช่ฉันเห็นด้วยที่เราต้องทำการวิเคราะห์เวลาแฝงแบบเต็มก่อนที่จะทำสิ่งนี้
Pramod S. Nikam

ใช่ฉันได้รับประสิทธิภาพการทำงานเดียวกันโดยใช้สิ่งนี้ไม่มีการปรับปรุง
mayank

1
ติดตามกระทู้นี้เพื่อหาทางออกที่ดีกว่าในการทำสิ่งนี้
Pramod S. Nikam

ฉันสามารถประมวลผลแบบขนานโดยใช้ ExecutorService ได้หรือไม่
mayank

1

คุณเพิ่มองค์ประกอบให้กับfinalListจากกระทู้ที่แตกต่างกันในเวลาเดียวกัน นี่เป็นสาเหตุที่ทำให้เกิดการผสมกฎการใช้คำสั่งซื้อต่างๆ (กฎไม่ได้ถูกจัดกลุ่มตามคำสั่งซื้อ)

คุณสามารถแก้ไขได้ด้วยการสร้างรายการชั่วคราวสำหรับแต่ละแล้วพร้อมผสานรายการชั่วคราวทั้งหมดในorderfinalList

นี่คือวิธีที่คุณสามารถทำได้โดยใช้ 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());

ขอบคุณสำหรับคำตอบ. ฉันลองใช้วิธีของคุณแล้วและฉันได้รับ java.util.ConcurrentModificationException: null
mayank

finalList = orders.parallelStream () .map (order -> rules.stream () .map (กฎ -> beanMapper.getBean (กฎ) .applyRule (createTemplate.apply (getMetaData.apply (กฎ) คำสั่ง) ลำดับ) .collect (Collectors.toList ())) เก็บ (Collectors.toList ()) สตรีม () flatMap (เก็บ :: กระแส) .collect (Collectors.toList (.))..;
mayank

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

ไม่จำเป็นต้องมีการสตรีมแม้แต่เพียงสองลูปซ้อนกัน ทดสอบ: 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


คำตอบเดิม

แต่มันกำลังเปลี่ยนกฎสำหรับคำสั่ง forEach (กฎ -> {}}

ไม่มันไม่ orders อาจทับซ้อน แต่คำสั่งของruleสำหรับการสั่งซื้อแต่ละครั้งจะถูกเก็บไว้ เหตุใดคนที่ไม่ขนานกัน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

คำสั่งของorderผสมกัน แต่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ส่วน ด้วยorders มองเห็นว่ามันสามารถติดตามได้ว่าrules ให้มาเป็น 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

ลำดับของการสั่งซื้อสามารถเป็นอะไรก็ได้ แต่ลำดับของกฎไม่ควรเปลี่ยนแปลง นอกจากนี้สำหรับกฎการสั่งซื้อเฉพาะควรมาเป็นกลุ่ม สำหรับอดีต (กฎ order1- 1 order1-Rule2 order1-Rule3) และไม่ใช่ (order1-Rule1 order2-Rule1 order1-Rule2 order1-Rule3)).
mayank Bisht

@ mayankbisht ฉันคิดว่าข้อ จำกัด เหล่านี้ไม่อนุญาตการประมวลผลแบบขนาน ดูคำตอบที่อัปเดต (ฉันเขียนส่วนใหม่ที่จุดเริ่มต้น)
tevemadar

ใช่ฉันเข้าใจแล้วและนั่นเป็นเหตุผลที่ฉันโพสต์คำถามนี้ที่นี่ ฉันคิดว่าอาจจะมีวิธีอื่นในการทำเช่นนี้หรือบางทีเราสามารถเปลี่ยนอัลโก
mayank

@ mayankbisht คุณสามารถอธิบายได้ว่าทำไมถึงorderไม่สามารถทับซ้อนกันได้ (เป็นของเหล่านั้นruleอาจเป็น stateful และมีอยู่ในจำนวน จำกัด สำเนาอาจเป็นหนึ่งเดียวเท่านั้น) แต่โดยทั่วไปแล้วจะไม่มีความเท่าเทียมกันหากไม่มีสิ่งใดที่ขนานกันนั่นคือจุดรวมของการขนานกัน
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.