这是我的Python代码:
X = [[0] * 1000] * 100
start = time()
for x in xrange(100):
for i in xrange(len(X)):
for j in xrange(len(X[i])):
X[i][j] += 1
print time() - start
我的Cython代码是一样的:
X = [[0] * 1000] * 100
start = time()
for x in xrange(100):
for i in xrange(len(X)):
for j in xrange(len(X[i])):
X[i][j] += 1
print time() - start
输出:
还有其他更快的方式在Python或Cython中做同样的事情吗?
更新:任何方法创建一个高度索引性能接近数组int X [] []的2d数组X在C / C ++中?
目前我正在考虑使用Python C API来完成这项工作。
还有一件事,一个numpy数组做同样的事情,但比纯Python和Cython中的列表慢得多(70秒)。
的Python:
X = np.zeros((100,1000),dtype=np.int32)
start = time()
for x in xrange(100):
for i in xrange(len(X)):
for j in xrange(len(X[i])):
X[i][j]+=1
如果对数字数组做了很多访问,哪种方法最好?
答案 0 :(得分:4)
要回答标题中的问题,您的Cython代码会击败您的Python代码,因为尽管缺少cdef
来声明变量,但仍会为for
循环生成C代码(除了许多额外的C代码来描述Python对象)。要加速Cython代码,请使用cdef
声明整数i
,j
和x
,以便它们不再是Python整数:例如cdef int i
。你也可以在Cython中declare C-type arrays进一步提高性能。
使用NumPy获得相同结果的快捷方法:
X = np.zeros((100, 1000), dtype=np.int32)
X += 10000
如果你可以提供帮助,你绝不应该对NumPy数组使用for
循环。它们与内存使用方面的列表完全不同。
答案 1 :(得分:1)
还有其他更快的方式在Python或Cython中执行相同的操作吗?
等效的,更快的代码将是:
X = [[100 * 100] * 1000] * 100
在您的代码中,您要创建一个1000
长的零列表,然后在该列表中创建一个100
长的引用列表。现在,在100
个长列表上重复100
次会导致每个位置递增100 * 100 = 10000
次。
len(set(map(id, X)))
1
如果您希望最终得到100
列表的列表:
base = [100] * 1000
X = [list(base) for _ in xrange(100)]
len(set(map(id, X)))
100
请注意,对列表中对象的引用仍然是仍然复制。
答案 2 :(得分:0)
ajcr的答案可能是最快最简单的答案。您应该首先在cython代码中显式声明变量的数据类型。另外,我会为外部循环创建一个prange
而不是一个简单的range
迭代器。这将激活OpenMP多线程,这可能会进一步加速你的代码,但我真的怀疑这个解决方案将胜过numpy实现。