在Python中,什么情况下SWIG比ctypes更适合调用共享库中的入口点?假设您没有SWIG接口文件。
这两者的性能指标是什么?
我有丰富的使用swig的经验。SWIG声称它是一种快速解决方案来包装各种东西。但在实际应用中...
SWIG开发的目标是通用性,适用于大多数人和20多种编程语言。这通常会导致以下缺点:
- 需要配置(SWIG .i 模板),有时很棘手,
- 没有处理某些特殊情况(请参见下文有关Python属性的说明),
- 对于某些语言而言性能不足。
Python缺点:
1)代码风格不一致。 C++ 和 Python 的代码风格非常不同(这显然是肯定的),因此 Swig 使目标代码更像 Python 的可能性非常有限。例如,从 getter 和 setter 创建属性是很困难的。详见 该问题和答案。
2)缺乏广泛的社区支持。 SWIG 有一些良好的文档。但如果遇到文档中没有涉及的问题,就找不到任何信息了。没有博客也无法通过谷歌获得帮助。在这种情况下,必须大量挖掘 SWIG 生成的代码... 真是可怕,我可以这样说...
在简单情况下,它真的很快速、简单和直接
如果您一旦生成了 swig 接口文件,就可以将此 C++ 代码包装到其他20多种语言中!
SWIG 的一个大问题是性能。自版本 2.04 起,SWIG 包括“-builtin”标志,使 SWIG 比其他自动包装方式更快。至少一些 基准测试 显示了这一点。
所以我得出结论,在以下两种情况下使用 swig 是不错的选择:
2) 如果需要将C++代码封装为多种语言或者可能需要将代码分发到多种语言中,使用SWIG是可靠的。
1) 如果只需要快速地封装一些来自某个C++库的函数以供最终使用,则可以使用SWIG。
更新:
我们使用SWIG转换我们的库已经过去了一年半。
首先,我们做了一个Python版本。在使用SWIG的过程中有几次遇到麻烦 - 这是真的。但是现在我们将库扩展到了Java和.NET。所以我们有了1个SWIG带着3种语言。我可以说在节省大量时间方面,SWIG非常棒。
更新 2:
我们使用SWIG已经两年了。SWIG已经集成到我们的构建系统中。最近我们对C++库进行了重大的API更改。SWIG表现得非常出色。我们需要做的唯一一件事就是向.i文件中添加几个%rename,这样我们的CppCamelStyleFunctions()
现在在Python中looks_more_pythonish
。起初我担心会出现一些问题,但一切都很顺利。只需要做几个编辑,所有东西都可以分发到3种语言中。现在我有信心,使用SWIG是我们的一个很好的解决方案。
更新 3:
我们已经使用SWIG将近3年了。 重大变化:Python部分完全重写为纯Python。原因是现在我们的库的大多数应用程序都使用Python。即使纯Python版本比C++封装版本工作得更慢,用户使用纯Python更方便,不必与本地库抗争。
SWIG仍然用于.NET和Java版本。
这里的主要问题是“如果我们从一开始就启动项目,是否会使用SWIG来编写Python代码?” 我们会! SWIG使我们能够快速将产品分发到许多语言中。它在一段时间内运作良好,为我们提供了更好地了解用户需求的机会。
SWIG生成(相当丑陋的)C或C++代码。对于简单函数(可以直接转换的内容),使用很简单,对于更复杂的函数(例如需要额外翻译步骤才能在Python中表示输出参数的函数),使用也相对容易。但是,对于更强大的交互,您通常需要编写C代码作为接口文件的一部分。除非使用简单功能,否则您需要了解CPython以及它如何表示对象--不难,但需要牢记。
ctypes允许您直接访问C函数、结构和其他数据,并加载任意共享库。这不需要编写任何C代码,但必须了解C语言的工作原理。可以这样说,它是SWIG的反面:不生成代码,运行时不需要编译器,但对于除简单用途之外的所有用途,确实需要了解诸如C数据类型、转换、内存管理和对齐方式的工作原理。您还需要手动或自动将C结构体、联合和数组转换为等效的ctypes数据结构,包括正确的内存布局。
在纯执行方面,SWIG可能比ctypes快--因为与Python运行时相比,编译时使用C来管理实际工作的开销较小。然而,除非您接口了许多不同的C函数,但每个都只使用几次,否则开销不太明显。
在开发时间方面,ctypes的启动成本要低得多:您不需要了解接口文件,也不需要生成.c文件并将其编译,也不需要检查和消除警告。您可以轻松地开始使用单个C函数,然后将其扩展到更多内容。而且,您可以直接在Python解释器中测试和尝试事物。包装大量代码有点乏味,尽管有尝试使其更简单的方法(例如ctypes-configure)。
另一方面,SWIG可用于为多种语言生成包装器(除了需要填充自定义C代码等语言特定细节之外)。如果要包装许多SWIG可以很容易处理的代码,则代码生成也比ctypes等效项简单得多。
CTypes非常酷,比SWIG要简单得多,但它的缺点是糟糕或恶意编写的Python代码实际上可能会使Python进程崩溃。您还应该考虑使用boost python。在我看来,它比swig更容易使用,同时还能让您对最终的Python接口拥有更多控制权。如果您已经在使用C++,那么您也不需要添加其他语言到您的混合中。
ctypes很好用,但不能处理C++类。我也发现ctypes比直接使用C绑定慢了约10%,但这将高度取决于您调用的内容。
如果您要使用ctypes,请务必查看Pyglet和Pyopengl项目,它们有大量的ctype绑定示例。
我想补充一些尚未提到的考虑因素。 [编辑:哎呀,没看到Mike Steder的回答]
如果您想尝试使用非Cpython实现(如PyPy、IronPython或Jython),那么ctypes是唯一可行的方法。 PyPy不允许编写C扩展,因此排除了pyrex / cython和Boost.python。出于同样的原因,ctypes是IronPython和(一旦他们将其全部工作都做好)jython的唯一可行机制。
正如其他人提到的,不需要编译。这意味着,如果新版本的.dll或.so发布,您只需将其放入并加载该新版本。只要没有更改任何接口,它就是一个无缝替换。
需要记住的是,SWIG 只针对 CPython 实现。由于 ctypes 也支持 PyPy 和 IronPython 实现,因此编写使用 ctypes 的模块可能更适用于与更广泛的 Python 生态系统兼容。