【发布时间】:2020-03-24 02:27:50
【问题描述】:
一直有人告诉我,python 的原生 append 是一个慢速函数,应该避免在 for 循环中使用。然而,经过几次小测试后,我发现在使用 for 循环对其进行迭代时,它的性能比 numpy 数组差:
第一次测试-数组/列表构造
python 原生列表追加
def pythonAppend(n):
x = []
for i in range(n):
x.append(i)
return x
%timeit pythonAppend(1000000)
Numpy 分配数组然后访问
def numpyConstruct(n):
x = np.zeros(n)
for i in range(n):
x[i] = i
return x
%timeit numpyConstruct(1000000)
结果:
Python 时间: 179 毫秒
Numpy 时间: 189 毫秒
第二次测试 - 访问元素
n = 1000000
x = pythonAppend(n)
arr = numpyConstruct(n)
order = arr[:]; np.random.shuffle(order); order = list(order.astype(int))
def listAccess(x):
for i in range(len(x)):
x[i] = i/3.
return x
def listAccessOrder(x, order):
for i in order:
x[i] = i/3.
return x
%timeit listAccess(x)
%timeit listAccess(arr)
%timeit listAccessOrder(x, order)
%timeit listAccessOrder(arr, order)
%timeit arr / 3.
结果
python 顺序: 175 毫秒
numpy -sequential: 198 毫秒
python -shuffled 访问: 2.08 秒
numpy -shuffled 访问: 2.15 秒
numpy 向量化访问: 1.92ms
这些结果对我来说非常令人惊讶,因为我认为至少由于 python 是链表访问元素会比 numpy 慢,因为必须遵循指针链。还是我误解了 python 列表的实现?另外,为什么 python 列表的性能略好于 numpy 等效项 - 我猜大部分效率低下来自使用 python for 循环,但 python 的 append 仍然在竞争 numpy 访问和分配。
【问题讨论】:
-
我猜当你在循环中松开 numpy 时,你会失去所有的性能优势。但是如果你可以把它写成一个向量函数,它会比用干净的python循环更快。
-
我认为 numpy 数组是连续的?因此,访问它们的元素(尤其是按随机顺序)会更快,因为 CPU 可以立即获取内存块,而不必遵循指向元素的一系列指针?
-
python 列表不是链表。
标签: python arrays performance numpy