vlambda博客
学习文章列表

指南:使用ctypes优化Python代码

注:本文中的代码是在GNU AGPLv3下授权的。


当我没有找到一个整体式的使用ctypes的指南时,我写了这个指南。希望这能让别人的生活更轻松一些。


基本优化


在用C语言重写Python源代码之前,请考虑一下这些标准的Python优化。


内置数据结构


Python中内置的数据结构(如set和dict)是用C编写的。它们比将你自己的数据结构编写为Python类要快得多。除了标准的set、dict、list和tuple之外,其他数据结构都记录在collections模块中。


列表推导式


与其向一个列表附加内容,不如使用列表推导式。


指南:使用ctypes优化Python代码

ctypes


ctypes是一个模块,它允许你通过Python代码与C代码进行通信,而不需要使用子进程或类似的模块来从CLI运行另一个进程。


这有两个部分:编译要作为共享对象加载的C代码,并在Python代码中设置数据结构,从而映射到C-types。


在这篇文章中,我将把我的Python代码连接到lcs.c,它可以找到两个字符串列表的最长公共子序列。在Python代码中,我想实现这样的效果:


指南:使用ctypes优化Python代码


这个特殊的C函数的一些挑战是函数签名的参数类型是字符串列表,而返回类型的长度不是固定的。我用一个包含指针和长度的Sequence结构来解决这个问题。


为Python编译C代码


首先,C源代码(lcs.c)被编译为可以被Python装载的lcs.so。


指南:使用ctypes优化Python代码

  • -Wall显示所有警告。

  • -Werrow将所有警告变为错误。

  • -fpic生成“位置无关的指令”,如果你想通过Python使用这个库,这是必须的。

  • -O3最大化优化。


接下来,我们开始编写Python代码来使用这个共享对象文件。


Python中的结构体


下面,我将展示我的C源代码中使用的两个结构体。


指南:使用ctypes优化Python代码

在这里,你可以看到结构体的Python翻译。


指南:使用ctypes优化Python代码


一些注解:


  • 所有结构体都是从ctypes.Structure继承的class。

  • 惟一的字段是_fields_,它是一个元组列表。每个元组是(<variable-name>, <ctypes.TYPE>)。

  • ctypes还有像c_char (char)和c_char_p (*char)这样的类型。

  • ctypes还包括POINTER(),它会从传递给它的任何类型创建一个指针类型。

  • 如果你有一个类似于CELL中的递归定义,则你必须传递初始声明,然后添加_fields_字段以供以后引用。

  • 由于我在我的Python代码中没有使用CELL,所以我不需要将这个结构体写出来,但是它在递归字段中有一个有趣的特性。


调用你的C代码


另外,你需要一些代码来将Python类型转换为新的C结构。最后,你可以使用新的C函数来加速Python代码。



更多注解:


  • **char(字符串列表)在Python中直接映射到字节列表。

  • lcs.c有一个函数lcs(),它的签名是:struct Sequence *lcs(struct Sequence *s1, struct Sequence *s2)。要设置其返回类型,我使用lcsmodule.lcs.restype = ctypes.POINTER(SEQUENCE)。

  • 为了调用一个对struct Sequence的引用,我使用ctypes.byref(),它返回一个指向你的对象的“轻量级指针”(比ctypes.POINTER()更快)。

  • common.items是一个字节列表,因此它们被解码后得到的ret将是一个str列表。

  • lcsmodule.freeSequence(common)只是释放与common相关的内存。这很重要,因为它不会被垃圾回收器(AFAIK)收集。


优化的Python代码: 你用C编写的代码,并用Python为它编写包装器。


额外扩展: PyPy

注:我个人从未使用过PyPy。


一个简单的优化就是在PyPy运行时中运行你的程序,其中包括一个即时(JIT)编译器,当代码循环多次运行时,它会通过将它们编译成本机代码来加速循环。


如果你有任何意见或想进一步讨论,请发邮件给我。


[相关链接]:https://www.youtube.com/watch?v=SHbS9tYFpcQ

Sam Stevens, 2019年

[源代码]:https://github.com/samuelstevens/personal-website


英文原文:https://samuelstevens.me/writing/optimizing-python-code-with-ctypes
译者:野生大熊猫