Stream reduction identity vs. 幂等值

Stream reduction identity vs. idempotent value

java.util.stream 包文档在缩减上下文中给出了 identity 的定义:

the identity value must be an identity for the combiner function. This means that for all u, combiner.apply(identity, u) is equal to u.

Stream.reduce() 及其原始版本提供了类似的定义。

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

但是这个定义似乎比支持并行性所必需的要严格。为什么不要求 idempotent value x, such that combiner.apply(x, x) is equal to x? This would protect functions like Integer::sum, (a, b) -> a * b and String::concat from skewing across multiple processes, while still allowing the use of any seed with idempotent functions like Math::max, (a, b) -> a | b and Sets::intersection.

是否有一些我忽略的身份值的独特优势?

为什么 combiner.apply(x, x) == x 身份 的良好定义?

假设组合器是 max()。当然,max(x, x) == x 是正确的。对于任何 x,这实际上都是正确的,这意味着 任何 值对于 max().

都是一个很好的 identity

这当然不是真的,因为 max() 组合器的唯一有效 identity 值是 MIN_VALUE(或 "no value",例如nullNaN,假设组合器理解并忽略这样的值)。

仅仅询问 "why not?" 并提供一些不会造成问题的示例是不够的。您必须提供证明,证明在这种宽松的要求下,顺序和并行评估可以保证产生相同的正确结果。

让我们使用 2 参数 reduce 来简化问题。让我们也将自己限制为具有 2 个元素的流(ab)。设恒等式为 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) 必须等于 a op b 对于任何关联 op 和任何 a b.

我能想到的一个反例是 space-折叠串联:(x, y) -> (x + y).replaceAll(" +", " ")。它是关联的," " 是幂等的,但不是关于此功能的恒等式。并行和顺序评估将产生不同的结果。