为什么使用Cython列表比使用Python列表更快?

时间:2014-08-19 08:23:34

标签: python performance list numpy cython

这是我的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费用:2.86秒
  • Cython成本:0.41秒

还有其他更快的方式在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

如果对数字数组做了很多访问,哪种方法最好?

3 个答案:

答案 0 :(得分:4)

要回答标题中的问题,您的Cython代码会击败您的Python代码,因为尽管缺少cdef来声明变量,但仍会为for循环生成C代码(除了许多额外的C代码来描述Python对象)。要加速Cython代码,请使用cdef声明整数ijx,以便它们不再是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实现。