python - 如何在 cython 中实现更好的循环速度性能?

标签 python python-3.x loops cython typed-memory-views

我已经开始了一个Python项目,它主要由循环组成。几天前,我读到了有关 cython 的内容,它可以帮助您通过静态类型获得更快的代码。 我开发了这两个函数来检查性能(一个在 python 中,另一个在 cython 中):

import numpy as np
from time import clock

size = 11
board = np.random.randint(2, size=(size, size))

def py_playout(board, N):
    black_rave = []
    white_rave = []
    for i in range(N):
        for x in range(board.shape[0]):
            for y in range(board.shape[1]):
                if board[(x,y)] == 0:
                    black_rave.append((x,y))
                else:
                    white_rave.append((x,y))
    return black_rave, white_rave

cdef cy_playout(board, int N):
    cdef list white_rave = [], black_rave = []
    cdef int M = board.shape[0], L = board.shape[1]
    cdef int i=0, x=0, y=0
    for i in range(N):
        for x in range(M):
            for y in range(L):
                if board[(x,y)] == 0:
                    black_rave.append((x,y))
                else:
                    white_rave.append((x,y))
    return black_rave, white_rave

我最终使用了下面的代码来测试性能:

t1 = clock()
a = playout(board, 1000)
t2 = clock()
b = playout1(board, 1000)
t3 = clock()

py = t2 - t1
cy = t3 - t2
print('cy is %a times better than py'% str(py / cy))

但是我没有发现任何明显的改进。我还没有使用过 Typed-Memoryviews。有人可以建议有用的解决方案来提高速度或帮助我使用 typed-memoryview 重写代码吗?

最佳答案

你是对的,如果不向 cython 函数中的 board 参数添加类型,加速并不会那么快:

%timeit py_playout(board, 1000)
# 321 ms ± 19.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit cy_playout(board, 1000)
# 186 ms ± 541 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

但速度仍然快了两倍。通过添加类型,例如

cdef cy_playout(int[:, :] board, int N):
    # ...

# or if you want explicit types:
# cimport numpy as np
# cdef cy_playout(np.int64_t[:, :] board, int N):  # or np.int32_t

速度快得多(几乎快了 10 倍):

%timeit cy_playout(board, 1000)
# 38.7 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

我还使用了 timeit (好吧,IPython 魔法 %timeit)来获得更准确的计时。


请注意,您还可以使用 无需任何额外的静态类型即可实现巨大的加速:

import numba as nb

nb_playout = nb.njit(py_playout)  # Just decorated your python function

%timeit nb_playout(board, 1000)
# 37.5 ms ± 154 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

关于python - 如何在 cython 中实现更好的循环速度性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45446052/

相关文章:

python - 在 python 3.X 中添加是/否确认

python - Scrapy spider 不会因使用 CloseSpider 扩展而终止

python - 从 Python 启动 Linux 守护进程

仅当定义了值时才更新 Python 字典

java - 向 pdf 添加文本?

javascript - 解释矩形递归 JavaScript 的工作原理

javascript - ie7 无法使用 javascript 循环遍历字符串

python - Pandas 数据框 : For loop that adds a fixed integer if the value exists in previous rows

python - 在 Python 中打开文件以进行独占访问的最佳方法是什么?

python - 如何将多个参数列表传递给@click.option