要以 PDF 格式阅读本主题,请点击此处。 |
GParsPool 并发集合处理
处理数据通常涉及操作集合。列表、数组、集合、映射、迭代器、字符串和许多其他数据类型都可以被视为项目的集合。处理此类集合的常见模式是按顺序逐个获取元素,并对每个元素进行操作。
例如,min() 函数应该返回集合中最小的元素。当您在数字集合上调用 min() 方法时,调用线程将创建一个 累加器 或 迄今为止最小的值,并将其初始化为给定类型的最小值,例如零。然后,线程将遍历集合中的元素,并将它们与 累加器 中的值进行比较。
处理完所有元素后,最小值将存储在 累加器 中。
这种算法虽然简单,但在多核硬件上是完全错误的。
在双核芯片上运行 min() 函数最多只能利用芯片50%的计算能力。在四核芯片上,它将只有 25%。
这种算法实际上浪费了 75% 的计算能力! |
正确!这种算法实际上浪费了 75% 的计算能力。
树状结构被证明更适合并行处理。我们示例中的 min() 函数不需要按顺序遍历所有元素,并将它们的值与 累加器 进行比较。相反,它可以利用硬件的多核特性。
例如,parallel_min() 函数可以比较集合中相邻值的对(或特定大小的元组),并将元组中最小的值提升到下一轮比较中。
在不同的元组中搜索最小值可以安全地并行进行,因此同一轮中的元组可以由不同的内核同时处理,而不会出现线程之间的竞争或争用。
GParsPool 类在集合上启用了基于ParallelArray(来自 JSR-166y)的 DSL。
使用示例
带有 Pool 的 GParsPool 示例
1
2
3
4
5
6
7
8
9
10
11
GParsPool.withPool {
def selfPortraits = images.findAllParallel{
it.contains me}.collectParallel {it.resize()
}
//a map-reduce functional style
def smallestSelfPortrait = images.parallel
.filter{it.contains me}
.map{it.resize()}
.min{it.sizeInMB}
}
GParsExecutorsPool 类提供了与 GParsPool 类类似的功能,但使用 JDK 线程池而不是更高效的基于ParallelArray(来自JSR-166y)的实现。
使用示例
GParsExecutorsPool.withPool
1
2
3
4
5
GParsExecutorsPool.withPool {
def selfPortraits = images
.findAllParallel{it.contains me}
.collectParallel {it.resize()}
}
有关更多信息,请参阅用户指南中的并行集合部分。