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",例如null
或 NaN
,假设组合器理解并忽略这样的值)。
仅仅询问 "why not?" 并提供一些不会造成问题的示例是不够的。您必须提供证明,证明在这种宽松的要求下,顺序和并行评估可以保证产生相同的正确结果。
让我们使用 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) 必须等于 a op b 对于任何关联 op 和任何 a 和 b.
我能想到的一个反例是 space-折叠串联:(x, y) -> (x + y).replaceAll(" +", " ")
。它是关联的," "
是幂等的,但不是关于此功能的恒等式。并行和顺序评估将产生不同的结果。
java.util.stream
包文档在缩减上下文中给出了 identity 的定义:
the
identity
value must be an identity for the combiner function. This means that for allu
,combiner.apply(identity, u)
is equal tou
.
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",例如null
或 NaN
,假设组合器理解并忽略这样的值)。
仅仅询问 "why not?" 并提供一些不会造成问题的示例是不够的。您必须提供证明,证明在这种宽松的要求下,顺序和并行评估可以保证产生相同的正确结果。
让我们使用 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) 必须等于 a op b 对于任何关联 op 和任何 a 和 b.
我能想到的一个反例是 space-折叠串联:(x, y) -> (x + y).replaceAll(" +", " ")
。它是关联的," "
是幂等的,但不是关于此功能的恒等式。并行和顺序评估将产生不同的结果。