【发布时间】:2017-12-16 16:28:25
【问题描述】:
在并行流上使用reduce() 操作时,the OCP exam book 声明reduce() 参数必须遵守某些原则。这些原则如下:
- 必须定义标识,以便对于流 u 中的所有元素,combiner.apply(identity, u) 等于 u。
- 累加器运算符 op 必须是关联的且无状态的,这样
(a op b) op c就等于a op (b op c)。- combiner 运算符还必须是关联的、无状态的并且与身份兼容,这样对于所有
u和tcombiner.apply(u, accumulator.apply(identity, t))都等于accumulator.apply(u,t)。
书中给出了两个例子来说明这些原理,请看下面的代码:
联想示例:
System.out.println(
Arrays.asList(1, 2, 3, 4, 5, 6)
.parallelStream()
.reduce(0, (a, b) -> (a - b)));
这本书是怎么说的:
它可能会输出 -21、3 或其他值作为累加器函数 违反了关联性。
身份要求示例:
System.out.println(
Arrays.asList("w", "o", "l", "f")
.parallelStream()
.reduce("X", String::concat));
这本书是怎么说的:
如果我们使用的身份参数不是 真正的身份价值。它可以输出
XwXoXlXf。作为 并行过程,标识应用于多个元素 流,导致非常意外的数据。
我不明白这些例子。在累加器示例中,累加器以0 - 1 开头,即-1,然后是-1 - 2,即-3,然后是-6,一直到-21。我明白,因为生成的数组列表不同步,结果可能由于竞争条件等的可能性而无法预测,但为什么累加器不是关联的? (a+b) 不会导致不可预知的结果吗?我真的不明白示例中使用的累加器有什么问题以及为什么它不是关联的,但是我仍然不完全理解“关联原则”的含义。
我也不明白身份示例。我知道如果 4 个单独的线程同时开始累积身份,结果确实可能是XwXoXlXf,但这与身份参数本身有什么关系?那么究竟什么才是合适的身份呢?
我想知道是否有人可以在这些原则上给我更多启发。
谢谢
【问题讨论】:
-
一切都在the documentation 中:“关联性 如果满足以下条件,则运算符或函数
op是关联的:(a op b) op c == a op (b op c)这对并行评估的重要性可以是看看我们是否将其扩展为四个术语:a op b op c op d == (a op b) op (c op d)所以我们可以同时评估(a op b)和(c op d),然后在结果上调用op。”有关有效身份值的示例,请参阅here -
应该强调来源
List的性质不是问题;并行流不需要同步列表。操作正在进行时不得修改源列表,但这也适用于顺序流。
标签: java parallel-processing java-8 java-stream reduce