在python中,在什么情况下SWIG比ctypes更适合在共享库中调用入口点?假设您还没有SWIG接口文件.
两者的性能指标是什么?
我有使用swig的丰富经验.SWIG声称它是包装物品的快速解决方案.但在现实生活中......
SWIG是针对每个人和20多种语言开发的.一般来说,它会带来一些缺点:
- 需要配置(SWIG .i模板),有时候很棘手,
- 缺乏对某些特殊情况的处理(进一步参见python属性),
- 缺乏某些语言的性能.
Python缺点:
1)代码风格不一致.C++和python具有非常不同的代码样式(当然很明显),使目标代码更加Python化的可能性非常有限.作为一个例子,从getter和setter创建属性是很重要的.看到这个q&a
2)缺乏广泛的社区.SWIG有一些很好的文档.但如果有人发现了文档中没有的内容,则根本就没有信息.没有博客或谷歌搜索有帮助.因此,在这种情况下,必须大量挖掘SWIG生成的代码......这太糟糕了,我可以说......
优点:
在简单的情况下,它非常快速,简单和直接
如果您生成一次swig接口文件,则可以将此C++代码包装为其他20多种语言(!!!).
关于SWIG的一个重要问题是表现.从版本2.04开始,SWIG包含'-builtin'标志,这使得SWIG比其他自动包装方式更快.至少有一些基准测试显示了这一点.
因此,当我使用swig时,我总结了两个案例:
2)如果需要为多种语言包装C++代码.或者,如果可能有时间需要分发多种语言的代码.在这种情况下,使用SWIG是可靠的.
1)如果需要从一些C++库中快速包装几个函数以供最终使用.
更新:
我们使用SWIG对库进行转换已经过了一年半.
首先,我们制作了一个python版本.有几次我们遇到SWIG的麻烦 - 这是真的.但是现在我们将库扩展为Java和.NET.所以我们有3种语言,1个SWIG.而且我可以说SWIG在节省大量时间方面发挥了作用.
更新2:
我们在这个库中使用SWIG已经两年了.SWIG已集成到我们的构建系统中.最近我们对C++库进行了重大的API更改.SWIG工作得很好.我们唯一需要做的就是为.i文件添加几个%重命名,这样我们CppCamelStyleFunctions()
现在就可以looks_more_pythonish
在python中了.首先,我担心可能出现的一些问题,但没有出错.这是惊人的.只需几种编辑,一切都以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更快 - 因为围绕实际工作的管理是在编译时在C中完成的,而不是在运行时在Python中完成的.但是,除非你接口很多不同的C函数但每次只有几次,否则开销不太可能真正引人注意.
在开发时,ctypes的启动成本要低得多:你不必学习接口文件,你不必生成.c文件并编译它们,你不必检查和静音警告.您可以轻松地跳入并开始使用单个C函数,然后将其扩展为更多.您可以直接在Python解释器中进行测试和尝试.包装大量代码有点单调乏味,尽管有人试图让它变得更简单(比如ctypes-configure).
另一方面,SWIG可用于生成多种语言的包装器(除非需要填写特定于语言的详细信息,例如我上面提到的自定义C代码.)当包装很多SWIG可以处理的代码时帮助,代码生成也可以比ctypes等效设置更简单.
CTypes非常酷,比SWIG容易得多,但它的缺点是编写得不好或恶意编写的python代码实际上会导致python进程崩溃.你还应该考虑使用boost python.恕我直言,它实际上比swig更容易,同时让你更好地控制最终的python界面.如果您仍在使用C++,那么您也不会添加任何其他语言.
根据我的经验,ctypes确实有一个很大的缺点:当出现问题时(并且它总是适用于任何复杂的接口),这是一个很难调试的地方.
问题是你的堆栈的很大一部分被ctypes/ffi魔术模糊了,并且没有简单的方法可以确定你是如何达到特定点的,以及为什么参数值是它们的原因.
您还可以使用Pyrex,它可以充当高级Python代码和低级C代码之间的粘合剂.例如,lxml是用Pyrex编写的.
我将成为逆向并建议,如果可以,您应该使用标准Python API编写扩展库.从C和Python的角度来看,它真的很好地集成了......如果你有使用Perl API的经验,你会发现它是一个非常令人愉快的惊喜.
Ctypes也很好,但正如其他人所说,它不会做C++.
你试图包装的图书馆有多大?代码库的变化速度有多快?还有其他维护问题吗?这些都可能会影响编写Python绑定的最佳方法的选择.
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的新版本,您可以将其删除,并加载该新版本.只要没有任何接口改变,它就是替代品的下降.