应用-Python C扩展的隐藏性能开销

目录

Python C扩展的隐藏性能开销

Python 很慢,而像 Rust、C 或 C++ 这样的编译语言则很快。因此,当你的应用程序运行得太慢时,将部分代码重写为编译扩展似乎是加速的自然选择。

不幸的是,编译扩展有时实际上比等效的 Python 代码更慢。即使它们更快,性能提升也可能远低于你的预期,这是由于两个因素导致的隐藏开销:

  1. 函数调用开销。
  2. 序列化/反序列化开销。

让我们看看这些隐藏的性能开销来自哪里,然后看看如何绕过它们。

问题 #1:调用开销

我们面临的第一个性能开销是函数调用。让我们用 Cython 编写一个函数,Cython 是一种编译为 C 的 Python 变体语言,看看运行它需要多长时间。

以下是 Cython 函数:

def do_nothing():
    pass

我们可以使用 IPython 的 %timeit 魔法函数来测量性能:

In [1]: from overhead_cython import do_nothing

In [2]: %timeit do_nothing()
30 ns ± 0.0352 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [3]: def py_do_nothing(): pass

In [4]: %timeit py_do_nothing()
62.5 ns ± 0.114 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

调用 Cython 函数比调用 Python 函数更快,这是事实。但即使是 30 纳秒,对于编译语言来说也相当慢:相比之下,C 函数调用另一个 C 函数可能只需要 3 纳秒,如果内联的话甚至更少。

问题 #2:(反)序列化开销

除了调用扩展的开销外,还有将参数传入函数并返回结果的开销。Python 表示对象的方式与 C 或 Rust 不同,因此需要进行转换。转换代码还需要错误处理以防失败。

结果是更多的开销。例如,这里有一个 Cython 函数,它接受一个 Python 整数列表,对它们求和并返回结果:

def sum(values):
    cdef long result = 0
    cdef long v
    for v in values:
        result += v
    return result

我们可以比较与 Python 的性能:

In [1]: from example_cython import sum as cython_sum

In [2]: l = list(ra
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李星星BruceL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值