栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

为什么在Python列表上执行“ for”要比在Numpy数组上执行“ for”更快?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

为什么在Python列表上执行“ for”要比在Numpy数组上执行“ for”更快?

我们可以花点时间找出答案:

>>> import numpy as np>>> a = np.arange(32)>>> aarray([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31])>>> a.data<read-write buffer for 0x107d01e40, size 256, offset 0 at 0x107d199b0>>>> id(a.data)4433424176>>> id(a[0])4424950096>>> id(a[1])4424950096>>> for item in a:...   print id(item)... 44249500964424950120442495009644249501204424950096442495012044249500964424950120442495009644249501204424950096442495012044249500964424950120442495009644249501204424950096442495012044249500964424950120442495009644249501204424950096442495012044249500964424950120442495009644249501204424950096442495012044249500964424950120

那么这是怎么回事?首先,我看了数组的内存缓冲区的内存位置。在

4433424176
。这本身并 不太有
启发性。但是,numpy将其数据存储为连续的C数组,因此numpy数组中的第一个元素 应对 应于数组本身的内存地址,但不这样:

>>> id(a[0])4424950096

但这不是一件好事,因为那会破坏python中的不变性,即2个对象

id
在其生命周期内永远不会具有相同的对象。

那么,numpy如何做到这一点?好吧,答案是numpy必须将返回的对象包装为python类型(例如

numpy.float64
numpy.int64
在这种情况下为),如果您逐项迭代1,则会花费时间。迭代时将进一步证明这一点-
我们看到,在数组上进行迭代时,我们在2个独立的ID之间交替。这意味着python的内存分配器和垃圾收集器正在超时工作以创建新对象,然后释放它们。

一个 名单 没有这个内存分配器/垃圾收集开销。列表中的对象已经作为python对象存在(并且它们在迭代后仍将存在),因此在列表的迭代中都没有任何作用。

时序方法:

另请注意,您的时间安排会因您的假设而有所偏离。您以为

k + 1
在两种情况下这应该花费相同的时间,但是事实并非如此。请注意,如果我重复您的时间 没有
做任何加法:

mgilson$ python -m timeit -s "import numpy" "for k in numpy.arange(5000): k"1000 loops, best of 3: 233 usec per loopmgilson$ python -m timeit "for k in range(5000): k"10000 loops, best of 3: 114 usec per loop

只有大约2倍的差异。但是,执行加法运算会导致相差约5倍:

mgilson$ python -m timeit "for k in range(5000): k+1"10000 loops, best of 3: 179 usec per loopmgilson$ python -m timeit -s "import numpy" "for k in numpy.arange(5000): k+1"1000 loops, best of 3: 786 usec per loop

为了好玩,让我们做一下添加:

$ python -m timeit -s "v = 1" "v + 1"10000000 loops, best of 3: 0.0261 usec per loopmgilson$ python -m timeit -s "import numpy; v = numpy.int64(1)" "v + 1"10000000 loops, best of 3: 0.121 usec per loop

最后,您的时间还包括不理想的列表/数组构建时间:

mgilson$ python -m timeit -s "v = range(5000)" "for k in v: k"10000 loops, best of 3: 80.2 usec per loopmgilson$ python -m timeit -s "import numpy; v = numpy.arange(5000)" "for k in v: k"1000 loops, best of 3: 237 usec per loop

注意,在这种情况下,numpy实际上离列表解决方案还很远。这表明 迭代 确实
慢一些,如果将numpy类型转换为标准python类型,则可能会加快速度。

1注意,切片时不会花费很多时间,因为那只需要分配O(1)新对象,因为numpy将 视图 返回到原始数组。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/639101.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号