流减少身份与幂等价值

时间:2017-10-11 23:35:52

标签: java parallel-processing java-stream reduction idempotent

java.util.stream包文档在缩减的上下文中为 identity 提供了这个定义:

  

identity值必须是组合器函数的标识。这意味着,对于所有ucombiner.apply(identity, u)等于u

Stream.reduce()及其原始对应物提供了类似的定义。

据我了解,这个定义对于支持并行流是必要的。例如,减少总和的非零种子值可以乘以并行处理器的数量,从而无法预测地扭曲最终结果。

但是这个定义似乎比支持并行性更加严格。为什么不要求idempotentx,以使combiner.apply(x, x)等于x?这样可以保护Integer::sum(a, b) -> a * bString::concat等函数不会偏移多个进程,同时仍允许使用具有幂等函数的任何种子,例如Math::max,{{1} }和Sets::intersection

我忽略的身份价值是否有一些独特的好处?

2 个答案:

答案 0 :(得分:4)

不足以问及为什么不这样做?"并提供一些不会导致问题的例子。您必须提供一个证明,即通过这种宽松的要求,可以保证顺序和并行评估能够产生相同的正确结果。

让我们使用2参数reduce来简化问题。我们还将自己限制为包含2个元素的流( a b )。让身份 i ,累加器为 op

按顺序评估时,结果为(i op a)op b 。当并行评估时,它可能是(i op a)op(i op b)(或者它们之间甚至可能存在裸 i ,但是让我们来看看它们。现在不用担心了。)我们希望这两者都等于 a op b

如果 i 需要是一个标识,很容易看出顺序和并行评估都是正确的。但是,如果 i 所需的全部是 i op i = i ,那么它显然不会遵循(i op a)op(i op b)对于任何关联 op 以及任何 a b 必须等于 a op b

我能想到的一个反例是空间崩溃连接:(x, y) -> (x + y).replaceAll(" +", " ")。它是关联的," "是幂等的,但不是关于此函数的身份。并行和顺序评估将产生不同的结果。

答案 1 :(得分:0)

为什么combiner.apply(x, x) == x能够很好地定义身份

说组合器是max()。当然,max(x, x) == x是真的。对于任何x实际上都是如此,这意味着任何值对于identity来说都是一个很好的max()值。

肯定不是这样,因为max()合并器的唯一有效标识值为MIN_VALUE(或“{无值”,例如nullNaN,假设组合者理解并忽略了这样的值。)