Cython 程序(打印 Hello world)比纯 Python 慢得多
Cython program (print Hello world) much slower than pure Python
我是 Cython 的新手。我写了一个超级简单的测试程序来获得 Cython 的好处。然而,我的纯 python 速度要快得多。难道我做错了什么?
test.py:
import timeit
imp = '''
import pyximport; pyximport.install()
from hello_cy import hello_c
from hello_py import hello_p
'''
code_py = '''
hello_p()
'''
code_cy = '''
hello_c()
'''
print(timeit.timeit(stmt=code_py, setup=imp))
print(timeit.timeit(stmt=code_cy, setup=imp))
hello_py.py:
def hello_p():
print('Hello World')
hello_cy.pyx:
from libc.stdio cimport printf
cpdef void hello_c():
cdef char * hello_world = 'hello from C world'
printf(hello_world)
hello_py时间耗时14.697s
hello_cy 耗时98s
我错过了什么吗?我怎样才能更快地调用 cpdef 函数 运行?
非常感谢!
它花费的时间太长,因为 pyximport 会即时编译 cython 代码(因此您也在测量从 cython 到 C 的编译以及从 C 代码到本机库的编译)。您应该测量调用已编译的代码 - 请参阅 https://cython.readthedocs.io/en/latest/src/quickstart/build.html#building-a-cython-module-using-setuptools
这不是一个有意义的测试 - 两个函数不一样:
- Python
print
打印一个字符串后跟一个换行符。我认为它会刷新输出。
printf
扫描字符串中的格式化字符(例如 %s
),然后在没有额外换行符的情况下打印它。默认情况下 printf
是行缓冲的(即在每个新行之后刷新)。由于您从不 post 换行或刷新它,因此管理越来越大的缓冲区可能会减慢它的速度。
总而言之,不要被毫无意义的微基准测试所误导。特别是对于终端 IO,这实际上很少成为限制因素。
我强烈怀疑你的配置有问题。
我已经(部分)在 Windows 10、Python 3.10.0、Cython 0.29.26、MSVC 2022 中重现了您的测试,并得到了完全不同的结果
因为在我的测试中,Cython 代码稍快一些。我做了 2 处更改:
在 hello_cy.pyx 中,为了使两个代码更接近,我添加了换行符:
...
printf("%s\n", hello_world)
在主脚本中我把函数的调用和时间的显示分开了:
...
pyp = timeit.timeit(stmt=code_py, setup=imp)
pyc = timeit.timeit(stmt=code_cy, setup=imp)
print(pyp)
print(pyc)
当我 运行 我得到的脚本(在你好几页之后...):
...
hello from C world
hello from C world
19.135732599999756
14.712803700007498
这看起来更像是预期的...
无论如何,我们真的不知道这里测试的是什么,因为尽可能不要测试 IO,因为它取决于程序本身之外的很多东西。
我是 Cython 的新手。我写了一个超级简单的测试程序来获得 Cython 的好处。然而,我的纯 python 速度要快得多。难道我做错了什么? test.py:
import timeit
imp = '''
import pyximport; pyximport.install()
from hello_cy import hello_c
from hello_py import hello_p
'''
code_py = '''
hello_p()
'''
code_cy = '''
hello_c()
'''
print(timeit.timeit(stmt=code_py, setup=imp))
print(timeit.timeit(stmt=code_cy, setup=imp))
hello_py.py:
def hello_p():
print('Hello World')
hello_cy.pyx:
from libc.stdio cimport printf
cpdef void hello_c():
cdef char * hello_world = 'hello from C world'
printf(hello_world)
hello_py时间耗时14.697s
hello_cy 耗时98s
我错过了什么吗?我怎样才能更快地调用 cpdef 函数 运行?
非常感谢!
它花费的时间太长,因为 pyximport 会即时编译 cython 代码(因此您也在测量从 cython 到 C 的编译以及从 C 代码到本机库的编译)。您应该测量调用已编译的代码 - 请参阅 https://cython.readthedocs.io/en/latest/src/quickstart/build.html#building-a-cython-module-using-setuptools
这不是一个有意义的测试 - 两个函数不一样:
- Python
print
打印一个字符串后跟一个换行符。我认为它会刷新输出。 printf
扫描字符串中的格式化字符(例如%s
),然后在没有额外换行符的情况下打印它。默认情况下printf
是行缓冲的(即在每个新行之后刷新)。由于您从不 post 换行或刷新它,因此管理越来越大的缓冲区可能会减慢它的速度。
总而言之,不要被毫无意义的微基准测试所误导。特别是对于终端 IO,这实际上很少成为限制因素。
我强烈怀疑你的配置有问题。
我已经(部分)在 Windows 10、Python 3.10.0、Cython 0.29.26、MSVC 2022 中重现了您的测试,并得到了完全不同的结果
因为在我的测试中,Cython 代码稍快一些。我做了 2 处更改:
在 hello_cy.pyx 中,为了使两个代码更接近,我添加了换行符:
... printf("%s\n", hello_world)
在主脚本中我把函数的调用和时间的显示分开了:
... pyp = timeit.timeit(stmt=code_py, setup=imp) pyc = timeit.timeit(stmt=code_cy, setup=imp) print(pyp) print(pyc)
当我 运行 我得到的脚本(在你好几页之后...):
...
hello from C world
hello from C world
19.135732599999756
14.712803700007498
这看起来更像是预期的...
无论如何,我们真的不知道这里测试的是什么,因为尽可能不要测试 IO,因为它取决于程序本身之外的很多东西。