伸びるpythonをswig、swigやウェ
質問
このボトルネックは私のpythonコードでは、遊具など。そして書こうと決めてc/c++の延長用です。
のswigほぼすかについて注意する必要はあり議論など。全てに働きます。
今の私の質問:swigを非常に大きなpyファイルは多くのcheckings"と"PySwigObject'の呼び出しの前には見込んでいます。pydいます。います。
などなたのご経験があるかもパフォーマンスを得る場合は手書きこのファイルにしましょうかswigいます。
解決
確かに手作業でこれを行うことで常にパフォーマンスが向上しますが、これを行うために必要な作業に比べてゲインは非常に小さくなります。私はあなたに与える数字はありませんが、インターフェースを手で維持する必要があるため、これはお勧めしません。あなたのモジュールが大きい場合、これはオプションではありません!
迅速な開発を望んでいたので、スクリプト言語を使用することを選択するのは正しいことでした。このようにして、早期最適化症候群を回避し、ボトルネックパーツを最適化することができます。ただし、C / pythonインターフェースを手動で行うと、確実に早期最適化症候群に陥ります。
インターフェイスコードが少ないものが必要な場合は、Cコードからdllを作成することを考え、そのライブラリをPythonから直接 cstruct 。
プログラムでpythonコードのみを使用する場合は、 Cython も検討してください。
他のヒント
swigを使用して他の言語のバインディングを生成する予定がない場合は、Boost.Pythonを検討する必要があります。
バインドする関数とクラスが多数ある場合、 Py ++ は自動的に機能する優れたツールですバインディングを作成するために必要なコードを生成します。
Pybindgen もオプションかもしれませんが、それは新しいプロジェクトであり、Boostの完成度は低くなります.Python。
編集:
たぶん私は賛否両論についてより明確にする必要があります。
-
Swig:
pro:多くのスクリプト言語のバインディングを生成できます。
cons:パーサーの動作が好きではありません。何らかの進歩があったかどうかはわかりませんが、2年前にはC ++パーサーがかなり制限されていました。ほとんどの場合、.hヘッダーをコピー/貼り付けする必要があり、いくつかの
%
文字を追加し、swigパーサーに追加のヒントを与えます。また、複雑ではない型変換のためにPython C-APIを時々処理する必要がありました。
もう使用していません。
-
Boost.Python:
pro: 非常に完全なライブラリです。これにより、C-APIで可能なすべてのことをC ++で行うことができます。このライブラリを使用してC-APIコードを記述する必要はありませんでした。また、ライブラリが原因でバグに遭遇したこともありません。バインディングのコードは、チャームのように機能するか、コンパイルを拒否します。
バインドするC ++ライブラリが既にある場合は、おそらく現在利用可能な最良のソリューションの1つです。ただし、書き換える小さなC関数しかない場合は、Cythonを使用することをお勧めします。
cons:事前にコンパイルされたBoost.Pythonライブラリがない場合は、Bjam(make replaceの一種)を使用します。私はBjamとその構文が本当に嫌いです。
B.Pで作成されたPythonライブラリは肥満になる傾向があります。また、それらをコンパイルするのに多く時間がかかります。
-
Py ++(廃止):Boost.Pythonが簡単になりました。 Py ++はC ++パーサーを使用してコードを読み取り、Boost.Pythonコードを自動的に生成します。また、著者からの素晴らしいサポートもあります(私ではありません;-))。
cons:Boost.Python自体に起因する問題のみ。更新:2014年現在、このプロジェクトは中止されているようです。
-
Pybindgen:
C-APIを処理するコードを生成します。 Pythonファイルで関数とクラスを記述するか、Pybindgenにヘッダーを読み取らせて自動的にバインディングを生成できます(このため、Py ++の作成者が作成したpythonライブラリであるpygccxmlを使用します)。
cons:これは若いプロジェクトであり、Boost.Pythonよりも小さなチームです。まだいくつかの制限があります。C++クラス、コールバックに対して多重継承を使用することはできません(ただし、自動的にではなく、カスタムコールバック処理コードを記述できます)。 Python例外のCへの翻訳。
間違いなく見栄えのする価値があります。
-
新しいもの: 2009/01/20に、Py ++の作者は新しいパッケージ C / C ++コードとpythonのインターフェイス。 ctypesに基づいています。まだ試していませんが、やります!注:このプロジェクトは、Py ++のように紛らわしいようです。
-
CFFI :最近までこの存在を知りませんでしたので、今のところ私の意見を述べることはできません。 Python文字列でC関数を定義し、同じPythonモジュールから直接呼び出すことができるようです。
-
Cython :これは、現在プロジェクトで使用している方法です。基本的に、特別な.pyxファイルにコードを記述します。これらのファイルはCコードにコンパイル(翻訳)され、CコードはCPythonモジュールにコンパイルされます。 Cythonコードは通常のPythonのように見えます(実際、純粋なPythonは有効な.pyx Cythonファイルです)。変数タイプのような。このオプションのタイピングにより、Cythonはより高速なCコードを生成できます。 Cythonファイルのコードは、純粋なPython関数だけでなく、CおよびC ++関数(およびC ++メソッド)も呼び出すことができます。
Cythonでは、同じコードでCとC ++の関数を呼び出し、PythonとCの変数を混合する、などと考えるのに時間がかかりました。しかし、それは非常に強力な言語であり、アクティブ(2014年)でフレンドリーなコミュニティがあります。
SWIG 2.0.4は、パフォーマンスを改善する新しい-builtinオプションを導入しました。 C ++拡張機能を高速で呼び出すサンプルプログラムを使用して、ベンチマークを行いました。 -builtinオプションの有無にかかわらず、boost.python、PyBindGen、SIP、およびSWIGを使用して拡張機能を構築しました。結果は次のとおりです(平均100回の実行):
SWIG with -builtin 2.67s
SIP 2.70s
PyBindGen 2.74s
boost.python 3.07s
SWIG without -builtin 4.65s
SWIGは最も低速でした。新しい-builtinオプションを使用すると、SWIGが最速のようです。
を使用 ウェ が良いと思います。ができますCの拡張Pythonのような書式で生成したCコードです。定型含まれます。のコードはpythonやらなければいけないということだけの数の変更はボトルネックのコードおよびCコードが生成されます。
例です。 hello.pyx
:
cdef int hello(int a, int b):
return a + b
を生成する 601ライン の定型コード:
/* Generated by Cython 0.10.3 on Mon Jan 19 08:24:44 2009 */
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "structmember.h"
#ifndef PY_LONG_LONG
#define PY_LONG_LONG LONG_LONG
#endif
#ifndef DL_EXPORT
#define DL_EXPORT(t) t
#endif
#if PY_VERSION_HEX < 0x02040000
#define METH_COEXIST 0
#endif
#if PY_VERSION_HEX < 0x02050000
typedef int Py_ssize_t;
#define PY_SSIZE_T_MAX INT_MAX
#define PY_SSIZE_T_MIN INT_MIN
#define PyInt_FromSsize_t(z) PyInt_FromLong(z)
#define PyInt_AsSsize_t(o) PyInt_AsLong(o)
#define PyNumber_Index(o) PyNumber_Int(o)
#define PyIndex_Check(o) PyNumber_Check(o)
#endif
#if PY_VERSION_HEX < 0x02060000
#define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt)
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size)
#define PyVarObject_HEAD_INIT(type, size) \
PyObject_HEAD_INIT(type) size,
#define PyType_Modified(t)
typedef struct {
void *buf;
PyObject *obj;
Py_ssize_t len;
Py_ssize_t itemsize;
int readonly;
int ndim;
char *format;
Py_ssize_t *shape;
Py_ssize_t *strides;
Py_ssize_t *suboffsets;
void *internal;
} Py_buffer;
#define PyBUF_SIMPLE 0
#define PyBUF_WRITABLE 0x0001
#define PyBUF_LOCK 0x0002
#define PyBUF_FORMAT 0x0004
#define PyBUF_ND 0x0008
#define PyBUF_STRIDES (0x0010 | PyBUF_ND)
#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES)
#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES)
#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES)
#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
#endif
#if PY_MAJOR_VERSION < 3
#define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
#else
#define __Pyx_BUILTIN_MODULE_NAME "builtins"
#endif
#if PY_MAJOR_VERSION >= 3
#define Py_TPFLAGS_CHECKTYPES 0
#define Py_TPFLAGS_HAVE_INDEX 0
#endif
#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3)
#define Py_TPFLAGS_HAVE_NEWBUFFER 0
#endif
#if PY_MAJOR_VERSION >= 3
#define PyBaseString_Type PyUnicode_Type
#define PyString_Type PyBytes_Type
#define PyInt_Type PyLong_Type
#define PyInt_Check(op) PyLong_Check(op)
#define PyInt_CheckExact(op) PyLong_CheckExact(op)
#define PyInt_FromString PyLong_FromString
#define PyInt_FromUnicode PyLong_FromUnicode
#define PyInt_FromLong PyLong_FromLong
#define PyInt_FromSize_t PyLong_FromSize_t
#define PyInt_FromSsize_t PyLong_FromSsize_t
#define PyInt_AsLong PyLong_AsLong
#define PyInt_AS_LONG PyLong_AS_LONG
#define PyInt_AsSsize_t PyLong_AsSsize_t
#define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
#define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
#define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y)
#else
#define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y)
#define PyBytes_Type PyString_Type
#endif
#if PY_MAJOR_VERSION >= 3
#define PyMethod_New(func, self, klass) PyInstanceMethod_New(func)
#endif
#if !defined(WIN32) && !defined(MS_WINDOWS)
#ifndef __stdcall
#define __stdcall
#endif
#ifndef __cdecl
#define __cdecl
#endif
#else
#define _USE_MATH_DEFINES
#endif
#ifdef __cplusplus
#define __PYX_EXTERN_C extern "C"
#else
#define __PYX_EXTERN_C extern
#endif
#include <math.h>
#define __PYX_HAVE_API__helloworld
#ifdef __GNUC__
#define INLINE __inline__
#elif _WIN32
#define INLINE __inline
#else
#define INLINE
#endif
typedef struct
{PyObject **p; char *s; long n;
char is_unicode; char intern; char is_identifier;}
__Pyx_StringTabEntry; /*proto*/
static int __pyx_skip_dispatch = 0;
/* Type Conversion Predeclarations */
#if PY_MAJOR_VERSION < 3
#define __Pyx_PyBytes_FromString PyString_FromString
#define __Pyx_PyBytes_AsString PyString_AsString
#else
#define __Pyx_PyBytes_FromString PyBytes_FromString
#define __Pyx_PyBytes_AsString PyBytes_AsString
#endif
#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
static INLINE int __Pyx_PyObject_IsTrue(PyObject* x);
static INLINE PY_LONG_LONG __pyx_PyInt_AsLongLong(PyObject* x);
static INLINE unsigned PY_LONG_LONG __pyx_PyInt_AsUnsignedLongLong(PyObject* x);
static INLINE Py_ssize_t __pyx_PyIndex_AsSsize_t(PyObject* b);
#define __pyx_PyInt_AsLong(x) (PyInt_CheckExact(x) ? PyInt_AS_LONG(x) : PyInt_AsLong(x))
#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
static INLINE unsigned char __pyx_PyInt_unsigned_char(PyObject* x);
static INLINE unsigned short __pyx_PyInt_unsigned_short(PyObject* x);
static INLINE char __pyx_PyInt_char(PyObject* x);
static INLINE short __pyx_PyInt_short(PyObject* x);
static INLINE int __pyx_PyInt_int(PyObject* x);
static INLINE long __pyx_PyInt_long(PyObject* x);
static INLINE signed char __pyx_PyInt_signed_char(PyObject* x);
static INLINE signed short __pyx_PyInt_signed_short(PyObject* x);
static INLINE signed int __pyx_PyInt_signed_int(PyObject* x);
static INLINE signed long __pyx_PyInt_signed_long(PyObject* x);
static INLINE long double __pyx_PyInt_long_double(PyObject* x);
#ifdef __GNUC__
/* Test for GCC > 2.95 */
#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else /* __GNUC__ > 2 ... */
#define likely(x) (x)
#define unlikely(x) (x)
#endif /* __GNUC__ > 2 ... */
#else /* __GNUC__ */
#define likely(x) (x)
#define unlikely(x) (x)
#endif /* __GNUC__ */
static PyObject *__pyx_m;
static PyObject *__pyx_b;
static PyObject *__pyx_empty_tuple;
static int __pyx_lineno;
static int __pyx_clineno = 0;
static const char * __pyx_cfilenm= __FILE__;
static const char *__pyx_filename;
static const char **__pyx_f;
static void __Pyx_AddTraceback(const char *funcname); /*proto*/
/* Type declarations */
/* Module declarations from helloworld */
static int __pyx_f_10helloworld_hello(int, int); /*proto*/
/* Implementation of helloworld */
/* "/home/nosklo/devel/ctest/hello.pyx":1
* cdef int hello(int a, int b): # <<<<<<<<<<<<<<
* return a + b
*
*/
static int __pyx_f_10helloworld_hello(int __pyx_v_a, int __pyx_v_b) {
int __pyx_r;
/* "/home/nosklo/devel/ctest/hello.pyx":2
* cdef int hello(int a, int b):
* return a + b # <<<<<<<<<<<<<<
*
*/
__pyx_r = (__pyx_v_a + __pyx_v_b);
goto __pyx_L0;
__pyx_r = 0;
__pyx_L0:;
return __pyx_r;
}
static struct PyMethodDef __pyx_methods[] = {
{0, 0, 0, 0}
};
static void __pyx_init_filenames(void); /*proto*/
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef __pyx_moduledef = {
PyModuleDef_HEAD_INIT,
"helloworld",
0, /* m_doc */
-1, /* m_size */
__pyx_methods /* m_methods */,
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL /* m_free */
};
#endif
static int __Pyx_InitCachedBuiltins(void) {
return 0;
return -1;
}
static int __Pyx_InitGlobals(void) {
return 0;
return -1;
}
#if PY_MAJOR_VERSION < 3
PyMODINIT_FUNC inithelloworld(void); /*proto*/
PyMODINIT_FUNC inithelloworld(void)
#else
PyMODINIT_FUNC PyInit_helloworld(void); /*proto*/
PyMODINIT_FUNC PyInit_helloworld(void)
#endif
{
__pyx_empty_tuple = PyTuple_New(0);
if (unlikely(!__pyx_empty_tuple))
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 1;
__pyx_clineno = __LINE__; goto __pyx_L1_error;}
/*--- Library function declarations ---*/
__pyx_init_filenames();
/*--- Initialize various global constants etc. ---*/
if (unlikely(__Pyx_InitGlobals() < 0))
{__pyx_filename = __pyx_f[0];
__pyx_lineno = 1;
__pyx_clineno = __LINE__;
goto __pyx_L1_error;}
/*--- Module creation code ---*/
#if PY_MAJOR_VERSION < 3
__pyx_m = Py_InitModule4("helloworld", __pyx_methods, 0, 0, PYTHON_API_VERSION);
#else
__pyx_m = PyModule_Create(&__pyx_moduledef);
#endif
if (!__pyx_m)
{__pyx_filename = __pyx_f[0];
__pyx_lineno = 1; __pyx_clineno = __LINE__;
goto __pyx_L1_error;};
#if PY_MAJOR_VERSION < 3
Py_INCREF(__pyx_m);
#endif
__pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME);
if (!__pyx_b)
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 1;
__pyx_clineno = __LINE__; goto __pyx_L1_error;};
if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0)
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 1;
__pyx_clineno = __LINE__; goto __pyx_L1_error;};
/*--- Builtin init code ---*/
if (unlikely(__Pyx_InitCachedBuiltins() < 0))
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 1;
__pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_skip_dispatch = 0;
/*--- Global init code ---*/
/*--- Function export code ---*/
/*--- Type init code ---*/
/*--- Type import code ---*/
/*--- Function import code ---*/
/*--- Execution code ---*/
/* "/home/nosklo/devel/ctest/hello.pyx":1
* cdef int hello(int a, int b): # <<<<<<<<<<<<<<
* return a + b
*
*/
#if PY_MAJOR_VERSION < 3
return;
#else
return __pyx_m;
#endif
__pyx_L1_error:;
__Pyx_AddTraceback("helloworld");
#if PY_MAJOR_VERSION >= 3
return NULL;
#endif
}
static const char *__pyx_filenames[] = {
"hello.pyx",
};
/* Runtime support code */
static void __pyx_init_filenames(void) {
__pyx_f = __pyx_filenames;
}
#include "compile.h"
#include "frameobject.h"
#include "traceback.h"
static void __Pyx_AddTraceback(const char *funcname) {
PyObject *py_srcfile = 0;
PyObject *py_funcname = 0;
PyObject *py_globals = 0;
PyObject *empty_string = 0;
PyCodeObject *py_code = 0;
PyFrameObject *py_frame = 0;
#if PY_MAJOR_VERSION < 3
py_srcfile = PyString_FromString(__pyx_filename);
#else
py_srcfile = PyUnicode_FromString(__pyx_filename);
#endif
if (!py_srcfile) goto bad;
if (__pyx_clineno) {
#if PY_MAJOR_VERSION < 3
py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname,
__pyx_cfilenm, __pyx_clineno);
#else
py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname,
__pyx_cfilenm, __pyx_clineno);
#endif
}
else {
#if PY_MAJOR_VERSION < 3
py_funcname = PyString_FromString(funcname);
#else
py_funcname = PyUnicode_FromString(funcname);
#endif
}
if (!py_funcname) goto bad;
py_globals = PyModule_GetDict(__pyx_m);
if (!py_globals) goto bad;
#if PY_MAJOR_VERSION < 3
empty_string = PyString_FromStringAndSize("", 0);
#else
empty_string = PyBytes_FromStringAndSize("", 0);
#endif
if (!empty_string) goto bad;
py_code = PyCode_New(
0, /*int argcount,*/
#if PY_MAJOR_VERSION >= 3
0, /*int kwonlyargcount,*/
#endif
0, /*int nlocals,*/
0, /*int stacksize,*/
0, /*int flags,*/
empty_string, /*PyObject *code,*/
__pyx_empty_tuple, /*PyObject *consts,*/
__pyx_empty_tuple, /*PyObject *names,*/
__pyx_empty_tuple, /*PyObject *varnames,*/
__pyx_empty_tuple, /*PyObject *freevars,*/
__pyx_empty_tuple, /*PyObject *cellvars,*/
py_srcfile, /*PyObject *filename,*/
py_funcname, /*PyObject *name,*/
__pyx_lineno, /*int firstlineno,*/
empty_string /*PyObject *lnotab*/
);
if (!py_code) goto bad;
py_frame = PyFrame_New(
PyThreadState_GET(), /*PyThreadState *tstate,*/
py_code, /*PyCodeObject *code,*/
py_globals, /*PyObject *globals,*/
0 /*PyObject *locals*/
);
if (!py_frame) goto bad;
py_frame->f_lineno = __pyx_lineno;
PyTraceBack_Here(py_frame);
bad:
Py_XDECREF(py_srcfile);
Py_XDECREF(py_funcname);
Py_XDECREF(empty_string);
Py_XDECREF(py_code);
Py_XDECREF(py_frame);
}
/* Type Conversion Functions */
static INLINE Py_ssize_t __pyx_PyIndex_AsSsize_t(PyObject* b) {
Py_ssize_t ival;
PyObject* x = PyNumber_Index(b);
if (!x) return -1;
ival = PyInt_AsSsize_t(x);
Py_DECREF(x);
return ival;
}
static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
if (x == Py_True) return 1;
else if (x == Py_False) return 0;
else return PyObject_IsTrue(x);
}
static INLINE PY_LONG_LONG __pyx_PyInt_AsLongLong(PyObject* x) {
if (PyInt_CheckExact(x)) {
return PyInt_AS_LONG(x);
}
else if (PyLong_CheckExact(x)) {
return PyLong_AsLongLong(x);
}
else {
PY_LONG_LONG val;
PyObject* tmp = PyNumber_Int(x); if (!tmp) return (PY_LONG_LONG)-1;
val = __pyx_PyInt_AsLongLong(tmp);
Py_DECREF(tmp);
return val;
}
}
static INLINE unsigned PY_LONG_LONG __pyx_PyInt_AsUnsignedLongLong(PyObject* x) {
if (PyInt_CheckExact(x)) {
long val = PyInt_AS_LONG(x);
if (unlikely(val < 0)) {
PyErr_SetString(PyExc_TypeError, "Negative assignment to unsigned type.");
return (unsigned PY_LONG_LONG)-1;
}
return val;
}
else if (PyLong_CheckExact(x)) {
return PyLong_AsUnsignedLongLong(x);
}
else {
PY_LONG_LONG val;
PyObject* tmp = PyNumber_Int(x); if (!tmp) return (PY_LONG_LONG)-1;
val = __pyx_PyInt_AsUnsignedLongLong(tmp);
Py_DECREF(tmp);
return val;
}
}
static INLINE unsigned char __pyx_PyInt_unsigned_char(PyObject* x) {
if (sizeof(unsigned char) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
unsigned char val = (unsigned char)long_val;
if (unlikely((val != long_val) || (long_val < 0))) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to unsigned char");
return (unsigned char)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE unsigned short __pyx_PyInt_unsigned_short(PyObject* x) {
if (sizeof(unsigned short) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
unsigned short val = (unsigned short)long_val;
if (unlikely((val != long_val) || (long_val < 0))) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to unsigned short");
return (unsigned short)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE char __pyx_PyInt_char(PyObject* x) {
if (sizeof(char) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
char val = (char)long_val;
if (unlikely((val != long_val) )) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to char");
return (char)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE short __pyx_PyInt_short(PyObject* x) {
if (sizeof(short) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
short val = (short)long_val;
if (unlikely((val != long_val) )) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to short");
return (short)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE int __pyx_PyInt_int(PyObject* x) {
if (sizeof(int) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
int val = (int)long_val;
if (unlikely((val != long_val) )) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to int");
return (int)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE long __pyx_PyInt_long(PyObject* x) {
if (sizeof(long) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
long val = (long)long_val;
if (unlikely((val != long_val) )) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to long");
return (long)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE signed char __pyx_PyInt_signed_char(PyObject* x) {
if (sizeof(signed char) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
signed char val = (signed char)long_val;
if (unlikely((val != long_val) )) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to signed char");
return (signed char)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE signed short __pyx_PyInt_signed_short(PyObject* x) {
if (sizeof(signed short) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
signed short val = (signed short)long_val;
if (unlikely((val != long_val) )) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to signed short");
return (signed short)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE signed int __pyx_PyInt_signed_int(PyObject* x) {
if (sizeof(signed int) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
signed int val = (signed int)long_val;
if (unlikely((val != long_val) )) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to signed int");
return (signed int)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE signed long __pyx_PyInt_signed_long(PyObject* x) {
if (sizeof(signed long) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
signed long val = (signed long)long_val;
if (unlikely((val != long_val) )) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to signed long");
return (signed long)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
static INLINE long double __pyx_PyInt_long_double(PyObject* x) {
if (sizeof(long double) < sizeof(long)) {
long long_val = __pyx_PyInt_AsLong(x);
long double val = (long double)long_val;
if (unlikely((val != long_val) )) {
PyErr_SetString(PyExc_OverflowError, "value too large to convert to long double");
return (long double)-1;
}
return val;
}
else {
return __pyx_PyInt_AsLong(x);
}
}
観察:pybindgen開発者によって実施されたベンチマークに基づいて、boost.pythonとswigの間に大きな違いはありません。 boost.python機能の適切な使用にどれだけ依存するかを検証するための独自のベンチマークは行っていません。
pybindgenが一般にswigやboost.pythonよりもかなり高速であると思われる理由があるかもしれないことに注意してください。たとえば、例外の伝播、引数の型チェックなど。私はまだpybindgenを使用する機会がありませんでしたが、そうするつもりです。
Boostは一般的にインストールするのに非常に大きなパッケージであり、最後に、Boostライブラリ全体を必要とするだけのboost Pythonをインストールすることはできないと見ました。他の人が述べたように、テンプレートプログラミングを頻繁に使用するため、コンパイルは遅くなります。これは、通常、コンパイル時の不可解なエラーメッセージも意味します。
概要:SWIGのインストールと使用がどれだけ簡単か、堅牢で汎用性のあるきちんとしたバインディングが生成されること、および1つのインターフェイスファイルでC ++ DLLをLUA、C#、Javaなどの他のいくつかの言語から利用できることを考えると、 boost.pythonよりも好きです。しかし、多言語サポートを本当に必要としない限り、そのスピードを理由にPyBindGenを詳しく調べ、生成されるバインディングの堅牢性と汎用性に細心の注意を払います。
速度とオーバーヘッドが心配なので、 PyBindGen を検討することをお勧めします。
これを使用して、大規模な内部C ++ライブラリをラップした経験があります。 SWIG、SIP、Boost.Pythonを試した後、次の理由からPyBindGenを好みます。
- PyBindGenラッパーは純粋なPythonであり、別のファイル形式を学ぶ必要はありません
- PyBindGenはPython C API呼び出しを直接生成します。SWIGのような速度を奪う間接層はありません。
- 生成されたCコードは簡潔で理解しやすいものです。 Cythonも好きですが、Cの出力を読み取ろうとするのは難しい場合があります。
- STLシーケンスコンテナがサポートされています(多くのstd :: vectorを使用しています)
ここにはドラゴンがいます。振り回さないで、ブーストしないでください。複雑なプロジェクトの場合、それらを機能させるために自分で入力する必要があるコードは、すぐに管理不能になります。ライブラリに対する単純なC API(クラスなし)の場合は、ctypesを使用できます。簡単で痛みがなく、必要な機能に関する小さなメモを見つけようとして、これらの迷路のようなラッパープロジェクトのドキュメントを何時間も探し回る必要はありません。
大きな拡張機能ではない場合、boost :: pythonもオプションである可能性があります。何が起こっているかを制御するため、swigよりも速く実行されますが、開発に時間がかかります。
単一の呼び出し内の作業量が十分に大きければ、とにかくswigのオーバーヘッドは許容できます。たとえば、C / C ++に移行したい中規模の論理ブロックがあるが、そのブロックはタイトループ内で呼び出されることが問題である場合、頻繁にスウィッグを避ける必要があるかもしれませんが、私は本当に考えられませんスクリプト化されたグラフィックシェーダーを除く実世界の例のすべて。
Pythonコードを放棄する前に、 ShedSkin をご覧ください。一部のコードでは、Psycoよりも優れたパフォーマンスを主張しています(また、まだ実験段階であると述べています)。
その他、C / C ++コードをPythonにバインドするにはいくつかの選択肢があります。
Boostはコンパイルに時間がかかりますが、実際には最も柔軟で使いやすいソリューションです。
SWIGを使用したことはありませんが、boostと比較すると、Python専用のフレームワークではなく、汎用バインディングフレームワークほど柔軟性がありません。
次の選択肢は Pyrex です。 C拡張としてコンパイルされる擬似Pythonコードを記述できます。
トピック Cython、pybind11、cffi <!>#8211;どのツールを選択すべきですか?
せっかちな人のための簡単な要約:
-
Cython は、PythonをC / C ++にコンパイルし、C / C ++をPythonコードに埋め込むことができます。静的バインディングを使用します。 Pythonプログラマ向け。
-
pybind11 (およびboost.python)は逆です。 C ++側からコンパイル時にものをバインドします。 C ++プログラマ向け。
-
CFFI を使用すると、実行時にネイティブのものを動的にバインドできます。簡単に使用できますが、パフォーマンスが低下します。