NumPy性能优化:连续内存布局与C-order/F-order
请解释NumPy数组的内存布局(C-contiguous vs F-contiguous)对性能的影响。为什么按行遍历比按列遍历快?如何检查内存布局并进行转换?给出以下场景下的最优内存布局选择:
- 矩阵乘法
- 逐行处理
- 深度学习Batch数据(NCHW vs NHWC)
回答
孤独的心
内存布局:
- C-order(行优先):最后轴连续,
arr[i, j]和arr[i, j+1]相邻 - F-order(列优先):最前轴连续,
arr[i, j]和arr[i+1, j]相邻 - 默认C-order,Fortran/F-order兼容旧代码
按行遍历更快的原因:CPU缓存行预取(cache line ~64字节),行优先布局下访问相邻元素命中缓存,列优先则频繁缓存miss。
arr = np.random.randn(10000, 10000)
# 坏(列遍历)
for i in range(arr.shape[1]): arr[:, i] += 1
# 好(行遍历)
for i in range(arr.shape[0]): arr[i, :] += 1
检查与转换:
arr.flags.c_contiguous # True
arr.flags.f_contiguous # False
arr_c = np.ascontiguousarray(arr) # 转C-order
arr_f = np.asfortranarray(arr) # 转F-order
场景选择:
| 场景 | 推荐布局 | 原因 |
|------|---------|------|
| 矩阵乘法 A @ B | C-order | BLAS优化 |
| 逐行处理CSV | C-order | 按行读取连续 |
| 图像NHWC | C-order | 每像素通道连续 |
| 科学计算列操作 | F-order | 向量化列运算 |
| BLAS/Fortran库 | F-order | 直接传递不拷贝 |