Python 확장-swig 또는 Cython이 아닌 swig로
나는 파이썬 코드에서 병목 현상을 발견했고, 사이코 등으로 놀았다. 그런 다음 성능을 위해 ac / c ++ 확장을 작성하기로 결정했다.
swig의 도움으로 거의 논쟁 등에 대해 신경 쓸 필요가 없습니다. 모든 것이 잘 작동합니다.
이제 내 질문 : swig는 실제 .pyd 또는 .so 코드를 호출하기 전에 많은 '검사'와 'PySwigObject'를 수행하는 상당히 큰 py 파일을 생성합니다.
이 파일을 직접 작성하거나 swig를 사용하여 더 많은 성능을 얻을 수 있는지 여부에 대한 경험이 있습니까?
확실히 손으로이 작업을 수행하면 항상 성능이 향상되지만이 작업을 수행하는 데 필요한 노력에 비해 이득은 매우 적습니다. 나는 당신에게 줄 그림이 없지만 이것을 권장하지 않습니다. 왜냐하면 당신은 손으로 인터페이스를 유지해야 할 것이기 때문입니다. 그리고 당신의 모듈이 큰 경우 이것은 옵션이 아닙니다!
신속한 개발을 원했기 때문에 스크립팅 언어를 사용하기로 선택했습니다. 이렇게하면 초기 최적화 증후군을 피할 수 있으며 이제 병목 부분을 최적화하려고합니다. 그러나 C / python 인터페이스를 손으로하면 확실히 초기 최적화 증후군에 빠질 것입니다.
더 적은 인터페이스 코드로 무언가를 원한다면 C 코드에서 dll을 만들고 cstruct를 사용하여 Python에서 직접 해당 라이브러리를 사용할 수 있습니다 .
프로그램에서 파이썬 코드 만 사용하려면 Cython 도 고려하십시오 .
swig를 사용하여 다른 언어에 대한 바인딩을 생성 할 계획이 없다면 Boost.Python을 고려해야합니다.
바인딩 할 함수와 클래스가 많은 경우 Py ++ 는 바인딩을 만드는 데 필요한 코드를 자동으로 생성하는 훌륭한 도구입니다.
Pybindgen 도 옵션 일 수 있지만 새로운 프로젝트이며 Boost.Python보다 덜 완성됩니다.
편집하다:
장단점에 대해 좀 더 명확하게 설명해야 할 수도 있습니다.
통음:
장점 : 많은 스크립팅 언어에 대한 바인딩을 생성 할 수 있습니다.
단점 : 파서가 작동하는 방식이 마음에 들지 않습니다. 진전이 있었는지 모르겠지만 2 년 전에는 C ++ 파서가 상당히 제한적이었습니다. 대부분의 경우 .h 헤더를 복사 / 붙여 넣기해야했습니다.
%
문자를 추가하고 swig 파서에 추가 힌트를 제공했습니다.또한 복잡한 유형 변환을 위해 때때로 Python C-API를 처리해야했습니다.
더 이상 사용하지 않습니다.
Boost.Python :
pro : 매우 완벽한 라이브러리입니다. C-API로 가능한 거의 모든 것을 C ++로 할 수 있습니다. 이 라이브러리로 C-API 코드를 작성할 필요가 없었습니다. 또한 라이브러리로 인해 버그가 발생하지 않았습니다. 바인딩 코드는 매력처럼 작동하거나 컴파일을 거부합니다.
바인딩 할 C ++ 라이브러리가 이미있는 경우 현재 사용 가능한 최상의 솔루션 중 하나 일 것입니다. 그러나 다시 작성할 작은 C 함수 만 있다면 Cython을 사용해 볼 것입니다.
단점 : 사전 컴파일 된 Boost.Python 라이브러리가없는 경우 Bjam (일종의 교체)을 사용하게됩니다. 나는 Bjam과 그 구문을 정말 싫어합니다.
BP로 만든 Python 라이브러리는 비만 해지는 경향이 있습니다. 또한 컴파일하는 데 많은 시간 이 걸립니다 .
Py ++ (단종 됨) : Boost.Python이 쉬워졌습니다. Py ++는 C ++ 파서를 사용하여 코드를 읽은 다음 Boost.Python 코드를 자동으로 생성합니다. 당신은 또한 그 저자의 큰 지원을 받고 있습니다 (아니, 그것은 내가 아닙니다 ;-)).
단점 : Boost.Python 자체로 인한 문제 만 있습니다. 업데이트 : 2014 년부터이 프로젝트는 중단 된 것으로 보입니다.
Pybindgen :
C-API를 다루는 코드를 생성합니다. Python 파일에서 함수와 클래스를 설명하거나 Pybindgen이 헤더를 읽고 자동으로 바인딩을 생성하도록 할 수 있습니다 (이를 위해 Py ++ 작성자가 작성한 Python 라이브러리 인 pygccxml을 사용합니다).
단점 : Boost.Python보다 작은 팀이있는 젊은 프로젝트입니다. 여전히 몇 가지 제한 사항이 있습니다. C ++ 클래스, 콜백에 대해 다중 상속을 사용할 수 없습니다 (자동이 아닌 사용자 지정 콜백 처리 코드를 작성할 수 있음). Python 예외를 C로 번역
확실히 좋은 볼 가치가 있습니다.
새로운 것 : 2009/01/20에 Py ++의 저자는 C / C ++ 코드를 파이썬과 인터페이스 하기위한 새로운 패키지 를 발표했습니다 . ctypes를 기반으로합니다. 나는 이미 그것을 시도하지 않았지만 나는 할 것이다! 참고 :이 프로젝트는 Py ++로 중단 된 것 같습니다.
CFFI : 최근까지도이게 존재하는지 몰랐기 때문에 지금은 내 의견을 말할 수 없습니다. Python 문자열에서 C 함수를 정의하고 동일한 Python 모듈에서 직접 호출 할 수있는 것처럼 보입니다.
Cython : 이것이 현재 제 프로젝트에서 사용하고있는 방법입니다. 기본적으로 특수 .pyx 파일에 코드를 작성합니다. 이러한 파일은 C 코드로 컴파일 (번역)되어 CPython 모듈로 컴파일됩니다. Cython 코드는 일반 Python처럼 보일 수 있지만 (실제로 순수한 Python은 유효한 .pyx Cython 파일 임) 변수 유형과 같은 더 많은 정보를 얻을 수도 있습니다. 이 선택적 입력을 통해 Cython은 더 빠른 C 코드를 생성 할 수 있습니다. Cython 파일의 코드는 순수 Python 함수뿐 아니라 C 및 C ++ 함수 (및 C ++ 메서드)도 호출 할 수 있습니다.
Cython에서 같은 코드에서 C와 C ++ 함수를 호출하고 Python과 C 변수를 혼합하는 등의 작업을하는 데 시간이 좀 걸렸습니다. 그러나 그것은 활동적이고 (2014 년에) 친근한 커뮤니티를 가진 매우 강력한 언어입니다.
SWIG 2.0.4는 성능을 향상시키는 새로운 내장 옵션을 도입했습니다. 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가 가장 느 렸습니다. 새로운 내장 옵션을 사용하면 SWIG가 가장 빠른 것 같습니다.
Cython을 사용하는 것은 꽤 좋습니다. Python과 유사한 구문으로 C 확장을 작성하고 C 코드를 생성하도록 할 수 있습니다. 보일러 플레이트가 포함되어 있습니다. 이미 파이썬에 코드가 있기 때문에 병목 코드를 몇 가지만 변경하면 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 기능의 적절한 사용에 달려 있는지 확인하기 위해 자체 벤치마킹을 수행하지 않았습니다.
Note also that there may be a reason that pybindgen seems to be in general quite a bit faster than swig and boost.python: it may not produce as versatile a binding as the other two. For instance, exception propagation, call argument type checking, etc. I haven't had a chance to use pybindgen yet but I intend to.
Boost is in general quite big package to install, and last I saw you can't just install boost python you pretty much need the whole Boost library. As others have mentioned compilation will be slow due to heavy use of template programming, which also means typically rather cryptic error messages at compile time.
Summary: given how easy SWIG is to install and use, that it generates decent binding that is robust and versatile, and that one interface file allows your C++ DLL to be available from several other languages like LUA, C#, and Java, I would favor it over boost.python. But unless you really need multi-language support I would take a close look at PyBindGen because of its purported speed, and pay close attention to robustness and versatility of binding it generates.
Since you are concerned with speed and overhead, I suggest considering PyBindGen .
I have experience using it to wrap a large internal C++ library. After trying SWIG, SIP, and Boost.Python I prefer PyBindGen for the following reasons:
- A PyBindGen wrapper is pure-Python, no need to learn another file format
- PyBindGen generates Python C API calls directly, there is no speed-robbing indirection layer like SWIG.
- The generated C code is clean and simple to understand. I like Cython too, but trying to read its C output can be difficult at times.
- STL sequence containers are supported (we use a lot of std::vector's)
There be dragons here. Don't swig, don't boost. For any complicated project the code you have to fill in yourself to make them work becomes unmanageable quickly. If it's a plain C API to your library (no classes), you can just use ctypes. It will be easy and painless, and you won't have to spend hours trawling through the documentation for these labyrinthine wrapper projects trying to find the one tiny note about the feature you need.
If its not a big extension, boost::python might also be an option, it executes faster than swig, because you control what's happening, but it'll take longer to dev.
Anyways swig's overhead is acceptable if the amount of work within a single call is large enough. For example if you issue is that you have some medium sized logic block you want to move to C/C++, but that block is called within a tight-loop, frequently, you might have to avoid swig, but I can't really think of any real-world examples except for scripted graphics shaders.
Before giving up on your python code, have a look at ShedSkin. They claim better performance than Psyco on some code (and also state that it is still experimental).
Else, there are several choices for binding C/C++ code to python.
Boost is lengthy to compile but is really the most flexible and easy to use solution.
I have never used SWIG but compared to boost, it's not as flexible as it's generic binding framework, not a framework dedicated to python.
Next choice is Pyrex. It allows to write pseudo python code that gets compiled as a C extension.
There is an article worth reading on the topic Cython, pybind11, cffi – which tool should you choose?
Quick recap for the impatient:
Cython compiles your python to C/C++ allowing you to embed your C/C++ into python code. Uses static binding. For python programmers.
pybind11 (and boost.python) is the opposite. Bind your stuff at compile time from the C++ side. For C++ programmers.
CFFI allows you to bind the native stuff dynamically at runtime. Simple to use, but higher performance penalty.
참고URL : https://stackoverflow.com/questions/456884/extending-python-to-swig-not-to-swig-or-cython
'Nice programing' 카테고리의 다른 글
Jackson ObjectMapper-객체 속성의 직렬화 순서 지정 (0) | 2020.11.26 |
---|---|
Jenkins 파이프 라인의 조건부 단계 / 단계 (0) | 2020.11.26 |
C #에서 다차원 키가있는 해시 테이블 (0) | 2020.11.26 |
포함 된 이미지가 포함 된 Multipart HTML 이메일 보내기 (0) | 2020.11.26 |
파일의 각 줄에서 선행 공백을 제거하는 방법 (0) | 2020.11.26 |