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

并行流java汇总

  •  2
  • orochi  · 技术社区  · 8 年前

    Java并行流总是并行执行每个操作并返回相同的结果?

    例如。

        IntStream of = IntStream.of(1, 2, 3);
        of = of.parallel();
    
        int reduce = of.reduce(0, (a,b) -> a + b);
        System.out.println("Result: " + reduce);
    

    4 回复  |  直到 8 年前
        1
  •  4
  •   Jan    7 年前

    我会尽力回答你的所有问题:

    1. of.reduce(0, (a,b) -> a + b);
      • 这个会吗 总是 返回相同的结果?(…始终返回6?)=&燃气轮机;对
      • 总是 并行执行=&燃气轮机;不
      • 他们会吗 总是
      • 他们会吗 总是

    #1、快速回答#

    属于减少(0,(a,b)->a+b);

    1.1.1这是否总是返回相同的结果?

    是的,无论你多久运行一次程序,它都会产生相同的结果。前提是JVM的实现和计算机(硬件和操作系统)工作正常。

    asks you to use an associative operation (您提供 (+) )和整数集的标识(您提供的 0 ). 更多信息请参见 出身背景 部分

    平行的 真正并行(同时进行不同的计算),那么问题的这一部分可以用一个明确的答案来回答 .

    1. 您的操作系统上的JVM可能只支持 用户级线程 。这是一种非常可移植的实现多线程行为的方法,即使它不是真正的多线程。这意味着,如果您的JVM只使用这样的“绿色线程”,那么即使您有多个CPU,这些线程也无法并行执行,因为您的内核不知道任何其他线程。关于这个的一些额外的wiki信息 here 但是正如wiki所说,绿色线程的实现在较新的JVM实现中并不常见,仅Squawk虚拟机似乎是最近的一个例外,截至年 this SO answer .

    2. “好吧,他想让我并行计算?!真的吗?!不,我会按顺序计算,因为为这种小计算创建额外线程太昂贵了!”

    另一方面,如果你

    1.2关于Java流上的所有操作

    1.2.1它们是否总是返回相同的结果?

    看见 第2.3.2节:并行流上的其他操作

    不,这里再次强调,本节中所写的观点是有效的 关于你的例子:这会一直并行吗

    此外,您可以实现或使用其他数据结构,并定义自己的收集操作,等等:

    如果您使用的数据结构过于同步,那么即使您使用多个线程,您的计算实际上也可能按顺序进行。也就是说,一个线程阻止所有其他线程进行进一步计算,直到自己完成为止。

    这个 简介 将介绍减少的功能以及为什么它可以在每种情况下成功地产生相同的结果。

    特定Java 添加了一些适用于Java中特定简化实现的信息。最后还有关于reduce以外的其他操作的信息。

    2.1简介

    我建议它将取决于您使用的函数和应用此函数的上下文(对象集)。

    在您的例子中,使用带整数(1,2,3)的函数(+)。

    (+)在整数集中有一些规则:

    • a+(b+c)=(a+b)+c

    总是

    得到了函数(+)和一个有序序列:(1,2,3)。

    假设有3个线程:

    • 收集器线程分配:(1,3)到线程1,(2,0)到线程2。
    • 1 + 3 和返回 4 到收集器线程。
    • 线程2计算: 2 + 0 和返回 2
    • 收集器线程计算: 4 + 2 = 6

    无序 这意味着,他不关心元素在序列中的顺序,随机分布计算,也只是按照子线程完成的顺序合并结果。

    2.3.1某些流。reduce(identity,someOrderedSequence)

    正如霍尔格在评论中所说,交换性质是不必要的。

    与我在一般情况下的*示例**相反,Java中此操作的收集器是 .确实如此 关心

    因为事实就是这样,Java的 IntStream 类对对象集和函数的属性限制较少:

    函数只需具有 ,表示(+): a + (b + c) = (a + b) + c .

    整齐

    java documentation

    int reduce(int identity,int二进制运算符op)

    使用提供的标识值和 关联累积函数,并返回减少的值。

    2.3.2并行流上的其他操作

    简介

    reduce(...) 函数,您的问题还包括关于一般情况的查询:

    问题的这一部分可以回答为“否”,因为它取决于您执行操作的操作和数据结构。

    有好将军 descriptions on using Streams in the Java specs

    状态

    Java文档本身提供了 an example of a stateful lambda expression on parallel streams :

     Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
    

    这里,如果并行执行映射操作,则结果 由于线程的原因,相同的输入可能因运行而异

    作为如何转换流管道的示例 表达式,并将匹配项放入列表中。

     ArrayList<String> results = new ArrayList<>();
     stream.filter(s -> pattern.matcher(s).matches())
           .forEach(s -> results.add(s));  // Unnecessary use of side-effects!
    

    ArrayList的非线程安全性将导致不正确的结果,。。。

    订购

    我在写Java的具体实现时已经谈到了排序,它只需要一个关联操作就可以始终返回相同的结果。

    from the Java specs

    如果流是有序的,则大多数操作都被限制在 元素的遭遇顺序;如果流的源是 包含[1,2,3]的列表,然后是执行映射的结果(x->x*2) 必须为[2,4,6]。但是,如果源没有定义的遭遇 顺序,则值[2,4,6]的任何排列都是有效的

    所以你可以再次考虑 一般情况下的示例 这里需要指出的是,即使序列和收集器是无序的,每次结果都必须是相同的,因为 (+) 在整数集中也具有交换性质。

    #3结论#

    如果你有一组假设作为问题的先决条件,那么答案可能更直接(例如特定的硬件功能、始终执行真正并行的JVM、始终有序的数据结构等等)。

        2
  •  2
  •   Eugene    8 年前

    如果您没有违反某些规则,并行或顺序将不会影响最终结果,例如,如果您编写:

    int reduce = of.reduce(10, (a,b) -> a + b); // notice the 10 instead of zero
    

    identity rule ...

    否则,并行运行操作将产生与顺序执行相同的结果。

        3
  •  1
  •   fps    8 年前

    它回来了 6 因为 1 + 2 + 3 = 6

    求和是否按 1 + (2 + 3) (1 + 2) + 3 ,或者只是 1 + 2 + 3

    Stream.reduce(identity, operator) 期望标识和 关联的 + 0 是此运算符的标识。只要你不违反合同 Stream.reduce

        4
  •  0
  •   Grzegorz Piwowarek    8 年前

    这取决于你在说什么手术。 reduce 只要提供关联合并函数,就会始终产生相同的结果。

    但是,例如,不能保证 findAny