并行与分布式系统中的并行前缀和(扫描)算法:Blelloch并行扫描算法
字数 1064 2025-11-04 00:21:09
并行与分布式系统中的并行前缀和(扫描)算法:Blelloch并行扫描算法
题目描述:
前缀和(也称扫描)操作是并行计算中的基础原语,定义为给定输入数组 [a₀, a₁, ..., aₙ₋₁],计算输出数组 [a₀, a₀⊕a₁, a₀⊕a₁⊕a₂, ..., a₀⊕a₁⊕...⊕aₙ₋₁],其中 ⊕ 是任意满足结合律的二元运算符(如加法、乘法)。Blelloch 算法是一种高效的工作最优并行扫描算法,它通过两阶段的树形结构(上扫和下扫)在 O(n/p + log n) 时间内完成计算,其中 p 为处理器数量。
解题过程:
-
问题分析
串行扫描需要 O(n) 时间。并行化的挑战在于前缀计算具有数据依赖性——每个输出值依赖前驱结果的累积。直接并行化会导致工作量非最优(如简单分块法需要 O(n log n) 总操作)。 -
算法核心思想
Blelloch 算法将计算分为两阶段:- 上扫(Reduce 阶段):构建一棵二叉树,自底向上计算局部和,但不存储中间前缀结果,仅保留子树和。
- 下扫(Down-Sweep 阶段):从树根向下传播前缀值,结合子树和生成最终前缀和。
-
数据结构准备
假设输入数组大小为 n(为简化设 n=2ᵏ)。创建长度为 2n 的数组arr,其中arr[n...2n-1]存储原始输入,arr[1...n-1]用于中间计算。 -
上扫阶段(Reduce)
- 从叶节点(索引 n 到 2n-1)开始,向上逐层合并:
for d from (log₂n - 1) down to 0: for k from 0 to (2^d - 1) in parallel: index = 2^d + k arr[index] = arr[2*index] ⊕ arr[2*index + 1] # 合并左右子节点 - 执行后,根节点
arr[1]存储全数组总和,但其他节点仅存储子树和。
- 从叶节点(索引 n 到 2n-1)开始,向上逐层合并:
-
下扫阶段(Down-Sweep)
- 将根节点前缀值设为单位元(如加法中为 0),然后向下传播:
arr[1] = 0 # 单位元 for d from 0 to (log₂n - 1): for k from 0 to (2^d - 1) in parallel: index = 2^d + k left = 2*index, right = 2*index + 1 arr[left] = arr[index] # 左子继承父节点前缀值 arr[right] = arr[index] ⊕ arr[left] # 右子前缀 = 父前缀 ⊕ 左子和 - 最终
arr[n...2n-1]存储完整前缀和(最后一个元素为总和)。
- 将根节点前缀值设为单位元(如加法中为 0),然后向下传播:
-
复杂度分析
- 总操作量:上扫和下扫各进行 n-1 次 ⊕ 操作,总计 2(n-1) 次,与串行算法相同(工作最优)。
- 并行时间:使用 n 个处理器时,每层并行执行,深度为 O(log n),总时间 O(log n)。
-
扩展优化
- 非 2 的幂次数组:填充单位元至最近幂次,最后截断结果。
- 分层并行:大规模数据可先分块局部扫描,再跨块合并(Blelloch 算法用于块间合并)。
实例验证(加法扫描,输入 [3,1,7,0]):
- 上扫后树:[-,11,4,7,3,1,7,0](索引1为根,存储总和11)
- 下扫后叶节点:[3,4,11,11] 即前缀和 [3, 3+1, 3+1+7, 3+1+7+0]。