大型numpy数组拼接的最快方法及循环耗时递增问题咨询
性能劣化原因
np.concatenate 执行时会重新申请适配新数组大小的连续内存空间,再将原数组全量数据、新数组数据依次拷贝到新内存中。循环内反复调用该方法时,随着数组体积增大,单次拷贝的数据量同步增长,最终呈现耗时线性上升的趋势。当循环次数为N时,累计拷贝的数据量是N*(N+1)/2倍单帧数组体积,循环次数越多冗余开销越高。
优化方案
方案1:预分配全量数组(已知总帧数场景首选)
提前申请容纳所有帧结果的完整数组,循环内直接按索引赋值,无额外内存申请和拷贝开销,耗时稳定最低。你更新后的代码就是该方案的实现,可进一步简化初始化逻辑:
import numpy as np import time frame_count = 100 arraySize = (256, 256) # 直接指定总帧数初始化数组,无需多次拼接生成 emptyArray = np.zeros((frame_count, *arraySize)) timeElapsed = [] for i in range(frame_count): start = time.time() newArray = np.zeros(arraySize) # 实际场景替换为光流计算结果 emptyArray[i] = newArray end = time.time() timeElapsed.append(end-start)
方案2:列表暂存后一次性合并(未知总帧数场景首选)
如果无法提前确定视频总长度,可先用Python列表暂存每帧的计算结果,全部帧处理完成后再做一次数组拼接,仅产生一次全量拷贝开销,性能远高于循环内拼接。
示例代码:
import numpy as np import time arraySize = (1, 256, 256) res_buffer = [] timeElapsed = [] # 循环次数不固定的场景也适用 for i in range(100): start = time.time() newArray = np.zeros(arraySize) # 实际场景替换为光流计算结果 res_buffer.append(newArray) end = time.time() timeElapsed.append(end-start) # 仅做一次合并生成最终数组 emptyArray = np.concatenate(res_buffer, axis=0)
两种方案都符合numpy生态的最佳实践,在长视频处理场景下性能提升幅度可达数十到数百倍。
内容的提问来源于stack exchange,提问作者Zac
相关产品推荐
相关产品推荐

