You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不同轴上Numpy求和运算的性能差异探究

Numpy不同尺寸数组沿不同轴求和速度反转的原因分析

我们知道Numpy默认采用**C顺序(行优先)**存储数组,理论上沿axis=1(行内求和)的内存访问是连续的,运算速度应该快于沿axis=0(列内求和)的非连续内存访问。但实际测试却出现了相反的结果:

小尺寸数组测试(64x64)

arr = np.ones([64, 64]) 
arr.flags
%timeit arr.sum(axis=1)  # 4.15 µs ± 97.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit arr.sum(axis=0)  # 4.67 µs ± 188 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

此时sum(axis=1)的速度符合理论预期,比sum(axis=0)更快。

大尺寸数组测试(10000x10000)

当数组尺寸放大后,结果完全反转:

arr = np.ones([10000, 10000])  
arr.flags
%timeit arr.sum(axis=1)  # 109 ms ± 2.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit arr.sum(axis=0)  # 57.5 ms ± 2.49 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

核心原因解析

  • 小尺寸数组:缓存命中率主导
    64x64的float64数组总大小仅32KB,完全能装进CPU的L1缓存。连续内存访问(axis=1)的缓存命中率接近100%,而非连续访问(axis=0)需要跨行跳转,缓存命中率稍低,所以sum(axis=1)更快。

  • 大尺寸数组:并行计算与缓存局部性的权衡
    10000x10000的数组总大小约763MB,远超过CPU缓存容量,此时缓存命中率不再是唯一核心因素:

    • 沿axis=0求和时,虽然内存访问是非连续的,但现代CPU的预取机制能针对固定跨步的访问做优化;更关键的是,列求和任务可以拆分成大量独立子任务,能充分利用多CPU核心的并行计算能力,抵消内存访问的劣势。
    • 沿axis=1求和时,虽然内存访问连续,但单一行的计算量小,多线程调度开销会抵消部分优势;同时,数组远大于缓存时,连续访问也会频繁触发缓存淘汰,内存带宽成为瓶颈,最终速度不如axis=0。
  • Numpy底层库的优化策略
    Numpy的sum函数依赖BLAS/LAPACK等高度优化的底层库,这些库会根据数组尺寸自动选择最优计算路径。对于大尺寸数组,BLAS库会优先启用多线程并行和SIMD指令,而axis=0的求和模式更适配这些优化策略,进一步放大了速度优势。

内容的提问来源于stack exchange,提问作者nan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 15:09:13