代码之家  ›  专栏  ›  技术社区  ›  chiperortiz

带极限+并行的java8 intstream

  •  0
  • chiperortiz  · 技术社区  · 7 年前

    我试图通过1Z0-809 Oracle认证,我只是在编写一些转储文件,最后我到了这里。

    public final class ParallelStreams{
       private long d=0,add=0,after=0;
       public static void main(String[] args){
           final ParallelStreams clazz = new ParallelStreams();
           IntStream.iterate(1,p->p+1)
                .peek(a->clazz.add++)
                .limit(5)
                .peek(a->clazz.after++)
                .parallel()
                .forEach(i->++clazz.d);
    
        System.out.println("clazz = " + clazz.d+" "+clazz.add+" "+clazz.after);
        }    
    }
    

    我知道这不是最好的办法。但有件事引起了我的注意。它的输出类似于

    clazz = 5 15451 5
    

    说1 peek方法被称为惊人的15451次,即使极限只有5次?这应该如何在所有线程中把握窥视,通过这段代码15451次,最终在流有5个线程时停止它?还是这样?

    对不起,如果问题很清楚,但对我来说很重要。

    2 回复  |  直到 7 年前
        1
  •  2
  •   Esteban Herrera    7 年前

    当我执行你的程序时,我得到了输出:

    clazz = 5 20 5
    

    添加一些打印语句:

    IntStream.iterate(1,p->p+1)
        .peek(a->{ System.out.println("add - " + a); clazz.add++; })
        .limit(5)
        .peek(a->{ System.out.println("after - " + a); clazz.after++; })
        .parallel()
        .forEach(i->{ System.out.println("d - " + i); ++clazz.d; });
    

    输出为:

    add - 1025
    add - 3073
    add - 1
    add - 6145
    add - 2
    add - 3074
    add - 1026
    add - 3075
    add - 3
    add - 6146
    add - 6147
    add - 4
    add - 3076
    add - 1027
    add - 3077
    add - 5
    add - 6148
    add - 6149
    add - 1028
    add - 1029
    after - 3
    after - 2
    after - 5
    d - 2
    d - 3
    d - 5
    after - 1
    after - 4
    d - 1
    d - 4
    clazz = 5 20 5
    

    为了理解这一点,这里有一些文档摘录。

    java.util.stream 以下内容:

    中间操作返回新流。它们总是懒惰的;执行诸如filter()之类的中间操作实际上并不执行任何筛选,而是创建一个新流,当遍历该流时,它包含与给定谓词匹配的初始流的元素。在执行管道的终端操作之前,管道源的遍历不会开始。

    IntStream.peek 以下内容:

    对于并行流管道,可以在任何时间调用该操作,也可以在上游操作使元素可用的任何线程中调用该操作。

    IntStream.limit 以下内容:

    虽然limit()在顺序流管道上通常是一个便宜的操作,但在有序的并行管道上可能会非常昂贵,特别是对于maxsize的大值,因为limit(n)被约束返回的不仅仅是任何n个元素,而是遇到顺序中的前n个元素。

    peek 不知道 limit 操作,所以之前随机执行n次 限制 执行。注意,一旦 after - d - 是打印的,没有与 add - 已打印。

    这些 之后- D- 行从1到5打印,但两者都不打印 偷看 也没有 forEach 使用并行流时,请确保流的顺序。

        2
  •  2
  •   Ravindra Ranwala    7 年前

    你在打电话 limit 在平行的溪流上。 限制 取决于遭遇顺序,当并行执行时,它必须缓冲所有之前的项,以确定是否将特定项推到下一步。因此,在做出决定之前,它会缓冲更多的项目。你的方法本质上是循序渐进的,你试图并行地执行它,这是非常不合理的,不会给你任何加速。解决这个问题的方法之一是 .parallel() 从你的河流管道里,

       IntStream.iterate(1,p->p+1)
            .peek(a->clazz.add++)
            .limit(5)
            .peek(a->clazz.after++)
            .forEach(i->++clazz.d);
    

    现在您将得到正确的结果。另一种解决方法是删除 IntStream.iterate 如下。

    IntStream.range(0, Integer.MAX_VALUE)
                    .peek(a->clazz.add++)
                    .limit(5)
                    .peek(a->clazz.after++)
                    .parallel()
                    .forEach(i->++clazz.d);
    

    这个解决方案可能会给你一些并行加速。