Python Numpy数组操作计时行为解析及系统冻结问题咨询
NumPy数组操作性能与系统冻结问题分析
测试代码
import numpy as np from time import perf_counter as T Shapes=[ (3,5), (30,50), (300,500), (3000, 5000), (30000, 50000) ] for shape in Shapes: h,w = shape a = np.arange(1,h*w+1,dtype=np.uint32).reshape(h,w) sT=T() b = np.flipud(np.fliplr(a.T).T) eT=T(); dT=eT-sT; print(f"{dT:.6f}", flush=True)
测试输出
0.000010 0.000008 0.000008 0.000072 0.000294
问题1:为何数组操作耗时未随数组尺寸增大而同步增长?
你用到的np.flipud、np.fliplr和数组转置.T都是视图操作,它们不会真的拷贝或移动内存里的数组元素,只是修改了数组的元数据(比如轴顺序、步长、形状描述),这个操作的时间是常数级的O(1),和数组大小无关。只有当操作无法通过元数据描述(比如需要生成非连续内存的数组)时才会触发数据拷贝,所以耗时不会随数组尺寸同步增长。
问题2:前三个尺寸(依次为100倍、10000倍增大)的计时处于同一区间,而后续1000000倍、100000000倍增大的数组计时却明显增加?
前三个尺寸的数组体积很小,完全能放进CPU的高速缓存(L1/L2/L3)中,视图操作的元数据修改几乎不花时间,所以计时稳定在同一区间。当数组尺寸超过缓存容量后,即使还是视图操作,后续的内存访问会触发缓存的加载与同步,产生额外开销。另外最后一个数组(30000x50000)的内存占用约6GB,已经接近你的物理内存(7.7Gi),此时内存调度的开销会明显上升,导致计时增加。
问题3:Linux Mint 21.2 Xfce系统(7.7Gi内存、2GB交换文件)多次运行该代码时会冻结,该现象为何出现,如何避免?
原因:
最后一个数组的内存占用约6GB,加上系统本身的内存消耗,很容易耗尽物理内存,触发交换分区(swap)的使用。交换文件基于磁盘,速度比内存慢几个数量级,系统大量读写交换分区时会陷入严重的IO等待,导致响应极慢甚至冻结。多次运行时,前一次的大数组内存可能未及时回收,叠加后内存占用超过物理内存+swap的总和,触发OOM(内存不足),进一步加剧系统卡顿。
避免方法:
- 移除测试列表中的
(30000, 50000)超大尺寸,改用内存占用在物理内存1/3以内的数组; - 每次循环后手动释放内存:导入
gc模块,在循环末尾添加del a, b; gc.collect(); - 暂时关闭其他占用内存的程序,减少系统内存压力;
- 若必须测试大数组,可适当增大交换分区,但这只能缓解,无法解决磁盘IO慢的核心问题。
内容的提问来源于stack exchange,提问作者user7711283
相关产品推荐
相关产品推荐

