为何启用Numba parallel=True后,可并行循环反而变慢?
Numba并行化后代码运行变慢的原因分析
你遇到的问题是启用Numba并行化后,代码执行时间反而显著增加,结合你的代码和测试场景,原因主要有以下几点:
单线程版本已被Numba极致优化
你的基础代码逻辑非常简单,仅对每个i执行少量算术运算和内存写入。Numba的njit模式会自动完成循环展开、寄存器分配、SIMD指令生成等深度优化,单线程就能把CPU的计算资源利用到接近极限,并行化很难再提升计算效率。并行化的额外开销远大于收益
使用prange开启并行时,需要完成线程创建、任务拆分与调度、线程同步等操作,这些都有固定的额外开销。而你的每个循环迭代计算量极小,这点开销完全抵消甚至超过了并行带来的计算收益,最终导致整体运行时间增加。内存访问模式的缓存效率下降
单线程版本中,代码按顺序访问数组元素,CPU缓存的命中率极高。并行化后,多个线程同时访问不同的内存区域,可能引发缓存竞争,或破坏原有的连续访问模式,导致缓存命中率降低,进一步拖慢运行速度。测试的数据集规模过小
你测试的n范围是2^0到2^14(即1到16384),这个量级下,并行化的固定开销占总运行时间的比例极高。只有当n达到百万级以上的大规模时,并行化的计算收益才可能超过开销,体现出优势。
基础单线程代码
@njit('f8[:,::1](f8[:,::1], f8[:,::1], f8[:,::1])', fastmath=True) def fun(A, B, C): n = A.shape[1] b00 = B[0,0] b02 = B[0,2] out = np.empty((n, 12)) for i in range(n): ui = A[0,i] c1 = C[0,i] c2 = C[1,i] c3 = C[2,i] c4 = C[3,i] out[i, 0] = c1 * b00 out[i, 1] = 0. out[i, 2] = c1 * (b02-ui) out[i, 3] = c2 * b00 out[i, 4] = 0. out[i, 5] = c2 * (b02-ui) out[i, 6] = c3 * b00 out[i, 7] = 0. out[i, 8] = c3 * (b02-ui) out[i, 9] = c4 * b00 out[i, 10] = 0. out[i, 11] = c4 * (b02-ui) return out
并行化版本代码
@njit('f8[:,::1](f8[:,::1], f8[:,::1], f8[:,::1])', fastmath=True, parallel=True) def fun_parallel(A, B, C): n = A.shape[1] b00 = B[0,0] b02 = B[0,2] out = np.empty((n, 12)) for i in prange(n): ui = A[0,i] c1 = C[0,i] c2 = C[1,i] c3 = C[2,i] c4 = C[3,i] out[i, 0] = c1 * b00 out[i, 1] = 0. out[i, 2] = c1 * (b02-ui) out[i, 3] = c2 * b00 out[i, 4] = 0. out[i, 5] = c2 * (b02-ui) out[i, 6] = c3 * b00 out[i, 7] = 0. out[i, 8] = c3 * (b02-ui) out[i, 9] = c4 * b00 out[i, 10] = 0. out[i, 11] = c4 * (b02-ui) return out
测试代码
B = np.random.rand(3,3) perfplot.show( setup=lambda n: (np.random.rand(2, n), np.random.rand(4, n)), kernels=[ lambda A, C: fun(A, B, C), lambda A, C: fun_parallel(A, B, C), ], labels=["fun", "fun_parallel"], n_range=[2**k for k in range(15)], xlabel="n", show_progress=False, )
内容的提问来源于stack exchange,提问作者abc
相关产品推荐
相关产品推荐

