Python:SWIG vs ctypes
在Python中,在什么情况下SWIG比ctypes更好的select共享库中的入口点? 假设您还没有SWIG接口文件。
这两个性能指标是什么?
SWIG生成(相当丑陋的)C或C ++代码。 使用简单的函数(可以直接翻译的东西)非常简单,而且可以很容易地用于更复杂的函数(例如带有输出参数的函数,需要额外的翻译步骤来在Python中表示)。需要将C的位作为接口文件的一部分写入。 除了简单的用法之外,你需要知道CPython以及它如何代表对象 – 不难,但要记住。
ctypes允许你直接访问C函数,结构和其他数据,并加载任意的共享库。 您不需要为此编写任何C,但是您需要了解C如何工作。 它可以说是SWIG的另一面:它不会生成代码,并且在运行时不需要编译器,但是除了简单的用途之外,它需要你理解C数据types,转换,内存pipe理和alignment工作。 您还需要手动或自动将C结构,联合和数组转换为等效的ctypes数据结构,包括正确的内存布局。
在纯执行中,SWIG可能比ctypes更快 – 因为围绕实际工作的pipe理是在编译时在C中完成的,而不是在运行时在Python中完成的。 但是,除非你连接了很多不同的C函数,但是每次只有几次,那么开销就不太可能是真正引人注目的了。
在开发时,ctypes的启动成本要低得多:您不必了解接口文件,也不必生成.c文件并编译它们,您不必检出并静默警告。 你可以直接跳入,用最小的努力开始使用一个C函数,然后将其扩展到更多。 而且你可以直接在Python解释器中testing和尝试。 包装大量的代码是有点繁琐的,尽pipe有人试图做到这一点(比如ctypes-configure)。
另一方面,SWIG可以用来生成多种语言的封装(禁止需要填写的语言特定的细节,就像我上面提到的自定义C代码一样)。当SWIG可以处理很多代码时帮助,代码生成也可以比ctypes等效更简单。
我有丰富的使用swig的经验。 SWIG声称这是包装物品的快速解决scheme。 但在现实生活中…
缺点:
SWIG被开发为一般,为所有人和20多种语言。 通常会导致缺点:
– 需要configuration(SWIG .i模板),有时很棘手,
– 缺乏对一些特殊情况的处理(进一步参见python属性),
– 缺less某些语言的performance。
Python缺点:
1) 代码风格不一致 。 C ++和python有很不相同的代码风格(这当然是显而易见的),使得目标代码更加恶性化的可能性非常有限。 举个例子,从getter和setter创build属性是很勉强的。 看到这个Q&A
2) 缺乏广泛的社区 。 Swig有一些很好的文档。 但是,如果有人抓到一些不在文件中的东西,根本就没有任何信息。 没有博客或谷歌search帮助。 所以在这种情况下,必须大量挖掘SWIG生成的代码…这太可怕了,我可以说…
特效:
-
在简单的情况下,它真的是快速,简单和直接
-
如果您一次生成swig接口文件,则可以将此C ++代码包装为任何其他20种以上的语言(!!!)。
-
关于SWIG的一个大问题是表演。 自2.04版本以来,SWIG包含了“builtin”标志,使SWIG甚至比其他自动化的包装方式更快。 至less有一些基准testing显示了这一点。
何时使用SWIG?
所以我总结了两个例子:
2)如果需要包装几种语言的 C ++代码。 或者,如果有可能有一个时间需要分发几种语言的代码。 在这种情况下使用SWIG是可靠的。
1)如果需要从一些C ++库中快速包装几个函数以供最终使用。
现场体验
更新 :
这是一年半的时间,因为我们使用SWIG对图书馆进行了转换。
首先我们制作了一个python版本。在SWIG遇到困难的时刻有一些 – 这是事实。 但是现在我们把库扩展到了Java和.NET。 所以我们有3个语言和1个SWIG。 我可以说, SWIG在节省很多时间方面是很有用的。
更新2 :
这个图书馆使用SWIG是两年。 SWIG集成在我们的构build系统中。 最近我们对C ++库进行了主要的API更改。 SWIG工作完美。 我们唯一需要做的就是将几个%重命名添加到.i文件,所以我们的CppCamelStyleFunctions()
现在looks_more_pythonish
了python中的looks_more_pythonish
。 首先,我担心可能会出现的一些问题,但没有出错。 这是惊人的。 只是几个编辑和一切分布在三种语言。 现在我相信,在我们的案例中使用SWIG是一个很好的解决scheme。
更新3 :
这是3年以上我们使用SWIG为我们的图书馆。 主要变化 :python部分完全用纯python重写。 原因是python现在用于我们图书馆的大部分应用程序。 即使纯Python版本的工作速度比C ++封装慢,但用户使用纯Python时更方便,而不是与本地库一起工作。
SWIG仍然用于.NET和Java版本。
这里的主要问题“如果我们从一开始就开始这个项目,我们会用SWIG来做python吗?”。 我们会! SWIG使我们能够将我们的产品快速分配到多种语言。 它工作了一段时间,使我们有机会更好地了解我们的用户需求。
CType非常酷,比SWIG容易得多,但是它的缺点是编写不好或恶意编写的python代码实际上可能会导致python进程崩溃。 你也应该考虑boost python。 恕我直言,它实际上比igig更容易,而让你更多的控制最终的Python界面。 如果您正在使用C ++,那么您也不要在其中添加任何其他语言。
根据我的经验,ctypes确实有一个很大的缺点:当出现问题时(对于任何复杂的接口它总是会出现这种情况),这是一个难以debugging的问题。
问题是你的堆栈的很大一部分被ctypes / ffi魔法所遮蔽,并且没有简单的方法来确定你是如何得到一个特定的点以及为什么参数值是他们是什么。
您也可以使用Pyrex ,它可以作为高级Python代码和低级C代码之间的粘合剂。 例如,lxml是用Pyrex编写的。
我将会逆向而且build议,如果可以的话,你应该使用标准的Python API编写扩展库。 从C和Python的angular度来看,它是非常好的集成……如果你有任何Perl API的经验,你会发现它是一个非常令人惊喜的事情。
Ctypes也不错,但是正如其他人所说的那样,C ++不会。
你试图包装的图书馆有多大? 代码库变化的速度有多快? 任何其他维修问题? 这些都可能会影响编写Python绑定的最佳方式的select。
ctypes很棒,但不处理C ++类。 我还发现ctypes比直接C绑定慢10%左右,但是这很大程度上取决于你所说的。
如果你打算去ctypes,一定要检查pyglet和pyopengl项目,有大量ctype绑定的例子。
只是想添加一些我没有看到提到的考虑。 [编辑:哎呀,没有看到麦克·斯德的回答]
如果您想尝试使用非Cpython实现(如PyPy,IronPython或Jython),那么ctypes是唯一的方法。 PyPy不允许编写C-extensions,这样就排除了pyrex / cython和Boost.python。 出于同样的原因,ctypes是唯一的机制,将为IronPython和(最终,一旦他们得到这一切工作)jython的工作。
正如别人提到的,不需要编译。 这意味着,如果新版本的.dll或.so出来,你可以把它放入,并加载新版本。 只要没有一个接口发生改变,这是一个替代品的下降。
需要注意的是,SWIG仅针对CPython实现。 由于PyPy和IronPython实现也支持ctypes,为了与更广泛的Python生态系统兼容,可能需要使用ctypes编写模块。
我发现SWIG在其方法(通常不仅仅是Python)方面有点臃肿,而且如果不用Python的代码编写的思路就可以让SWIG友好,而不是写得干干净净Python代码 它是,恕我直言,一个更直接的过程写C绑定到C + +(如果使用C + +),然后使用ctypes接口到任何C层。
如果您正在连接的库具有C接口作为库的一部分,则ctypes的另一个优点是您不必编译单独的python绑定库来访问第三方库。 在制定一个纯粹的python解决scheme时,这是非常好的,避免了跨平台编译问题(针对在不同平台上提供的第三方库)。 必须将编译好的代码embedded到你希望以PyPi的方式以跨平台友好的方式部署的包中,这是一件痛苦的事情; 关于使用SWIG或底层显式C代码的Python包最恼人的一点是他们的跨平台不可用性。 因此,如果您正在使用跨平台的可用第三方库并围绕它们开发python解决scheme,请考虑这一点。
作为一个真实的例子,考虑PyGTK。 这(我相信)使用SWIG生成C代码接口到GTK C调用。 我用这个最简单的时间才发现它是一个真正的痛苦,build立和使用,奇怪的奇怪的错误,如果你没有按照正确的顺序安装和一般的事情。 这是一个令人沮丧的经验,当我在网上查看由GTK提供的interace定义时,我意识到将这些接口的翻译器编写成python ctypes接口是一个简单的练习。 一个名为PyGGI的项目诞生了,有一天,我能够重写PyGTK,使它成为一个function更强大,更实用的产品,它与GTK面向对象的接口完全匹配。 而且它不需要编译C代码就可以跨平台友好。 (我实际上是在连接到webkitgtk之后,它不是那么跨平台的)。 我也可以很容易地将PyGGI部署到任何支持GTK的平台上。