【发布时间】:2017-03-21 23:17:59
【问题描述】:
我正在将 python 脚本转换为 cython 并对其进行优化以提高速度。现在我有 2 个版本,在我的台式机上,V2 的速度是 V1 的两倍,不幸的是,在我的笔记本电脑上,V1 的速度是 V2 的两倍,我无法找出为什么会有如此大的差异。
两台电脑都使用:
- Ubuntu 16.04
- Python 2.7.12
- Cython 0.25.2
- Numpy 1.12.1
桌面:
- Intel® Core™ i3-4370 CPU @ 3.80GHz × 4 64bit。 16GB 内存
笔记本电脑:
- Intel® Core™ i5-3210 CPU @ 2.5GHz × 2 64bit。 8GB 内存
V1 - 你可以找到完整的代码here。所做的唯一更改是将go.py、preprocessing.py 重命名为go.pyx、preprocessing.pyx 并使用import pyximport; pyximport.install() 编译它们。你可以运行test.py。此版本使用 2d numpy 数组 board 将数据存储在 go.pyx 中,并使用 preprocessing.pyx 中的 get_board 函数中的列表理解来处理数据。在测试期间,没有从 go.py 调用任何函数,只使用了 numpy 数组 board
V2 - 你可以找到完整的代码here。相当多的东西已经改变,你可以在下面找到一个列表,其中列出了影响这个测试用例的所有内容。请注意,所有函数和变量声明都必须在go.pxd 中。您可以使用以下命令运行test.py:python test.py build_ext --inplace
2d numpy 数组被替换为:
cdef char board[ 362 ]
go.pyx 中的函数 get_board_feature 替换了 numpy 列表理解:
cdef char get_board_feature( self, short location ):
# return correct board feature value
# 0 active player stone
# 1 opponent stone
# 2 empty location
cdef char value = self.board[ location ]
if value == EMPTY:
return 2
if value == self.player_current:
return 0
return 1
preprocessing.pyx 中的get_board 函数被替换为循环遍历数组并为每个位置调用go.pyx 中的get_board_feature 的函数
@cython.boundscheck(False)
@cython.wraparound(False)
cdef int get_board(self, GameState state, np.ndarray[double, ndim=2] tensor, int offSet ):
"""A feature encoding WHITE BLACK and EMPTY on separate planes, but plane 0
always refers to the current player and plane 1 to the opponent
"""
cdef short location
for location in range( 0, state.size * state.size ):
tensor[ offSet + state.get_board_feature( location ), location ] = 1
return offSet + 3
如果我应该包含任何其他信息或运行某些测试,请告诉我。
cmp、差异测试
V2 go.c 和 preprocessing.c 文件是相同的。
V1 不生成.c 文件进行比较
更新比较 .so 文件
V2 go.so 文件不同:
goD.so goL.so differ: byte 473, line 1
preprocessing.so 文件是相同的,不知道该怎么想..
【问题讨论】:
-
我的感觉是代码太多,我无法深入研究(我怀疑其他人也会有同样的感觉)。一般建议是:我首先尝试分析它(在两个系统上),看看你是否能确定哪些函数显示了分析数据的巨大差异。如果你能做到这一点,那么你可能只使用显示主要区别的函数来构建一个更小的测试用例。
-
我要在问题中包含的第二件事是两个系统中 CPU 的详细信息。例如,一个 32 位和另一个 64 位 - 我可以想象这会在首选数据类型方面产生重大影响?
-
好吧,只有我提到的东西被使用,但我明白你的意思,并将创建一个干净的版本以提高可读性。关于 CPU 的要点我将添加该信息
-
我还会仔细检查生成的编译模块是否相同(
diff或cmp)。我想他们应该是,但如果不是,那可能是值得一看的。 -
我删除了所有未使用的代码,因此代码应该可读,只需要在 V1 的
go.py上添加说明,因为只使用了 numpy 数组。
标签: numpy optimization cython baduk