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

np.array行提取耗时疑问:为何子数组访问耗时更长?

为什么x的访问耗时远小于x[a]?

这是个特别有意思的反直觉问题,拆解开numpy的底层操作逻辑就一目了然了:

1. %timeit x其实没做“实际工作”

当你执行%timeit x时,Python只是返回了变量x的内存引用——说白了就是告诉解释器“这个变量在内存里的位置是啥”,完全没有触碰数组里的实际数据,也没有任何计算、内存分配或复制操作。这种纯引用操作的耗时几乎可以忽略,所以才会只有23纳秒。

2. x[a]是完整的“数组索引+数据复制”流程

而x[a]就不一样了,numpy要完成一整套实打实的操作:

  • 首先校验索引a的合法性:确认它符合numpy索引规则,检查索引的维度、取值范围是否正确;
  • 然后计算结果数组的形状:根据原数组x的形状和a的长度,确定新数组的维度(这里x是(100,20),a是长度20的数组,所以x[a]会生成一个(20,20)的新数组);
  • 最后也是最耗时的步骤:分配新内存+复制数据。numpy会为新数组开辟独立的内存空间,然后把原数组中对应索引位置的元素逐一复制过去。内存读写的开销远大于单纯的CPU运算,这就是1.7微秒耗时的核心原因。

3. 矩阵乘法的类似现象也源于同一逻辑

你提到的x.T.dot(x)和x[a].T.dot(x[a])的差异,本质也是一样的:

  • x.T.dot(x)直接基于原数组的连续内存做运算,numpy可以调用BLAS等高效线性代数库做深度优化,没有额外的前置开销;
  • 而x[a].T.dot(x[a])首先要完成上面说的索引+数据复制步骤,生成新数组后再做矩阵乘法,自然总耗时会更长。

额外提个小技巧:如果你的索引是连续的(比如这里的a=np.arange(20)),可以用切片x[:20]代替数组索引——切片返回的是原数组的视图(view),不会复制数据,耗时会和x的引用操作接近很多!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:43:24