문제

나는 파이썬 코드에서 병목 현상을 발견하고 Psycho 등과 함께 연주 한 다음 성능을 위해 AC/C ++ 확장자를 작성하기로 결정했습니다.

SWIG의 도움으로 논쟁 등을 신경 쓰지 않아도됩니다. 모든 것이 잘 작동합니다.

이제 내 질문 : SWIG는 실제 .pyd 또는 .so 코드를 호출하기 전에 많은 '체크'및 'pyswigobject'를 수행하는 상당히 큰 py-file을 만듭니다.

이 파일을 손으로 쓰거나 SWIG를하도록 할 경우 더 많은 성능을 얻을 수 있는지 여부에 대한 경험이 있습니까?

도움이 되었습니까?

해결책

확실히 당신은 항상 손 으로이 작업을 수행하는 성능 이득을 가질 것이지만, 이익은이를 수행하는 데 필요한 노력에 비해 매우 작을 것입니다. 나는 당신에게 줄 수있는 그림이 없지만 이것을 권장하지 않습니다. 왜냐하면 당신은 인터페이스를 손으로 유지해야하기 때문에, 이것은 당신의 모듈이 큰 경우 옵션이 아닙니다!

빠른 발전을 원했기 때문에 스크립팅 언어를 사용하기로 선택한 올바른 일을했습니다. 이렇게하면 초기 최적화 증후군을 피했으며 이제 병목 현상 부품을 최적화하고 싶습니다. 그러나 C/Python 인터페이스를 손으로 수행하면 초기 최적화 증후군에 확실히 떨어질 것입니다.

인터페이스 코드가 적은 것을 원한다면 C 코드에서 DLL을 작성하는 것에 대해 생각하고 Python에서 직접 해당 라이브러리를 사용할 수 있습니다. cstruct.

고려하십시오 시톤 프로그램에서 Python 코드 만 사용하려는 경우

다른 팁

SWIG와 함께 다른 언어에 대한 바인딩을 생성 할 계획이 없다면 Boost.python을 고려해야합니다.

바인딩 할 기능과 클래스가 많으면 py ++ 바인딩을하기 위해 필요한 코드를 자동으로 생성하는 훌륭한 도구입니다.

Pybindgen 옵션이 될 수도 있지만 새로운 프로젝트이며 Boost.python이 덜 완료됩니다.


편집하다:

아마도 프로와 단점에 대해 더 명확해야 할 수도 있습니다.

  • 통음:

    프로 : 많은 스크립팅 언어에 대한 바인딩을 생성 할 수 있습니다.

    단점 : 파서의 작동 방식이 마음에 들지 않습니다. 나는 약간의 진전을 이루었는지 모르겠지만 2 년 전 C ++ 파서는 상당히 제한적이었습니다. 대부분의 시간은 내 .H 헤더를 복사/지나쳐야했습니다. % 캐릭터와 SWIG 파서에 추가 힌트를 제공합니다.

    또한 복잡한 유형 변환을 위해 때때로 Python C-API를 다루어야했습니다.

    나는 더 이상 그것을 사용하지 않습니다.

  • boost.python :

    프로 : 매우 완전한 도서관입니다. C-API에서 가능한 거의 모든 것을 수행하지만 C ++에서 수행 할 수 있습니다. 이 라이브러리로 C-API 코드를 작성할 필요가 없었습니다. 또한 라이브러리로 인해 버그가 발생하지 않았습니다. 바인딩 코드는 매력처럼 작동하거나 컴파일을 거부합니다.

    이미 바인딩 할 C ++ 라이브러리가있는 경우 현재 사용 가능한 최고의 솔루션 중 하나 일 것입니다. 그러나 다시 작성할 작은 C 함수 만 있으면 Cython을 사용해 볼 것입니다.

    단점 : 사전 컴파일 된 boost.python 라이브러리가없는 경우 BJAM (교체품)을 사용하게됩니다. 나는 정말로 Bjam과 그 구문을 싫어합니다.

    BP로 만든 파이썬 라이브러리는 비만이되는 경향이 있습니다. 또한 a 많은 그들을 컴파일 할 시간입니다.

  • Py ++ (Discontinued) : Boost.python이 쉽게 만들었습니다. PY ++는 C ++ 파서를 사용하여 코드를 읽은 다음 roost.python 코드를 자동으로 생성합니다. 당신은 또한 저자로부터 큰 지원을 받았습니다 (아니요.

    단점 : Boost.python 자체로 인한 문제 만. 업데이트 : 2014 년 현재이 프로젝트는 이제 중단 된 것으로 보입니다.

  • Pybindgen :

    C-API를 다루는 코드를 생성합니다. Python 파일의 함수와 클래스를 설명하거나 Pybindgen이 헤더를 읽고 바인딩을 자동으로 생성하도록 할 수 있습니다 (이를 위해 Py ++의 저자가 작성한 Python 라이브러리 인 Pygccxml을 사용합니다).

    단점 : Boost.python보다 작은 팀이있는 젊은 프로젝트입니다. 여전히 몇 가지 제한 사항이 있습니다. C ++ 클래스, 콜백에 여러 상속을 사용할 수 없습니다 (자동으로는 아니지만 사용자 정의 콜백 처리 코드가 작성 될 수 있음). Python 예외의 C로의 번역

    확실히 좋은 모습을 볼 가치가 있습니다.

  • 새로운 것 : 2009/01/20에 PY ++의 저자는 새 패키지 Python과 C/C ++ 코드를 인터페이스하는 경우. CTypes를 기반으로합니다. 나는 이미 그것을 시도하지 않았지만 나는 할 것이다! 참고 :이 프로젝트는 PY ++로 중단 된 것 같습니다.

  • CFFI: 나는 최근 까지이 것의 존재를 알지 못했기 때문에 지금은 내 의견을 제시 할 수 없습니다. Python 문자열에서 C 함수를 정의하고 동일한 Python 모듈에서 직접 호출 할 수 있습니다.

  • 시톤: 이것은 현재 내 프로젝트에서 내가 사용하고있는 방법입니다. 기본적으로 특수 .pyx 파일로 코드를 작성합니다. 이러한 파일은 C 코드로 컴파일 (변환)으로 CPYTHON 모듈로 컴파일됩니다. Cython 코드는 일반 파이썬처럼 보일 수 있지만 실제로 순수한 파이썬은 유효한 .pyx cython 파일입니다). 이 선택적 입력을 통해 Cython은 더 빠른 C 코드를 생성 할 수 있습니다. Cython 파일의 코드는 순수한 파이썬 기능뿐만 아니라 C 및 C ++ 기능 (및 C ++ 메소드)을 호출 할 수 있습니다.

    Cython에서 동일한 코드 C 및 C ++ 함수, Python 및 C 변수를 혼합하는 등을 생각하는 데 시간이 걸렸습니다. 그러나 활발한 (2014 년) 친근한 커뮤니티가있는 매우 강력한 언어입니다.

SWIG 2.0.4는 성능을 향상시키는 새로운 구축 옵션을 도입했습니다. C ++ 확장에 대한 많은 빠른 호출을 수행하는 예제 프로그램을 사용하여 벤치마킹을했습니다. Buost.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가 가장 빠른 것 같습니다.

사용 시톤 꽤 좋습니다. 파이썬과 같은 구문으로 C 확장을 작성하고 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 사이에는 큰 차이가 없습니다. 나는 이것이 얼마나 많은 벤치마킹을 수행하지 않았다.

또한 Pybindgen이 일반적으로 Swig와 Boost.python보다 약간 빠른 것처럼 보이는 이유가있을 수 있습니다. 5월 다른 두 가지와 마찬가지로 다재다능한 바인딩을 생산하지 않습니다. 예를 들어, 예외 전파, 통화 인수 유형 검사 등. 아직 Pybindgen을 사용할 기회는 없었지만 의도합니다.

부스트는 일반적으로 설치하기에 상당히 큰 패키지이며, 마지막으로 부스트 파이썬을 설치할 수는 없다는 것을 알았습니다. 전체 부스트 라이브러리가 필요합니다. 다른 사람들이 언급했듯이 템플릿 프로그래밍을 많이 사용하여 컴파일이 느려질 것입니다. 이는 일반적으로 컴파일 시간에 크리프트 오류 메시지를 의미합니다.

요약 : SWIG가 설치 및 사용이 얼마나 쉬운 지, 강력하고 다재다능한 괜찮은 바인딩을 생성하고 하나의 인터페이스 파일이 C ++ DLL을 LUA, C#및 Java와 같은 다른 여러 언어에서 사용할 수있게 해줍니다. Boost.python 이상. 그러나 여러분이 실제로 다국어 지원이 필요하지 않으면 Pybindgen이 속도로 인해 면밀히 살펴보고, 생성하는 바인딩의 견고성과 다양성에 세심한주의를 기울일 것입니다.

속도와 오버 헤드에 관심이 있기 때문에 Pybindgen .

큰 내부 C ++ 라이브러리를 감싸는 데 사용한 경험이 있습니다. Swig, Sip 및 Boost.python을 시도한 후 다음과 같은 이유로 Pybindgen을 선호합니다.

  1. Pybindgen 래퍼는 순수한 파이썬이므로 다른 파일 형식을 배울 필요가 없습니다.
  2. Pybindgen은 Python C API 호출을 직접 생성하며 SWIG와 같은 속도로 묶는 간접 레이어는 없습니다.
  3. 생성 된 C 코드는 깨끗하고 이해하기 쉽습니다. 나는 Cython도 좋아하지만 C 출력을 읽는 것은 때때로 어려울 수 있습니다.
  4. STL 시퀀스 컨테이너가 지원됩니다 (우리는 많은 std :: vector 's를 사용합니다)

여기 드래곤이 있습니다. Swig하지 말고 부스트하지 마십시오. 복잡한 프로젝트의 경우 코드를 작성하려면 자신을 채워야합니다. 라이브러리에 대한 일반 C API 인 경우 (클래스 없음) CTYPES 만 사용할 수 있습니다. 쉽고 고통스럽지 않을 것이며, 필요한 기능에 대한 작은 메모를 찾으려고 노력하는이 미로 래퍼 프로젝트의 문서를 통해 트롤링하는 데 몇 시간을 소비 할 필요가 없습니다.

큰 확장이 아닌 경우 Boost :: Python도 옵션이 될 수 있으며 SWIG보다 빠르게 실행됩니다. 발생하는 일을 제어하기 때문에 DEV에 더 오래 걸립니다.

어쨌든 SWIG의 오버 헤드는 단일 통화 내의 작업량이 충분히 크면 허용됩니다. 예를 들어, C/C ++로 이동하려는 중간 크기의 로직 블록이 있다는 것이 문제가되지만 해당 블록은 단단한 루프 내에서 호출되므로 종종 SWIG를 피해야 할 수도 있지만 실제로 생각할 수는 없습니다. 스크립트 그래픽 셰이더를 제외한 모든 실제 예제.

파이썬 코드를 포기하기 전에 Shedskin. 그들은 일부 코드에서 psyco보다 더 나은 성능을 주장합니다 (또한 여전히 실험적이라고 말합니다).

그렇지 않으면 C/C ++ 코드를 Python에 바인딩하기위한 몇 가지 선택이 있습니다.

부스트는 컴파일이 길지만 실제로 가장 유연하고 사용하기 쉬운 솔루션입니다.

나는 SWIG를 사용한 적이 없지만 부스트와 비교할 때 Python 전용 프레임 워크가 아니라 일반적인 바인딩 프레임 워크만큼 유연하지 않습니다.

다음 선택은 파이렉스. C 확장으로 컴파일되는 의사 파이썬 코드를 작성할 수 있습니다.

주제에 대해 읽을 가치가있는 기사가 있습니다 Cython, Pybind11, CFFI - 어떤 도구를 선택해야합니까?

참을성이 없다는 신속한 요약 :

  • 시톤 Python을 C/C ++로 컴파일하여 C/C ++를 Python 코드에 포함시킬 수 있습니다. 정적 바인딩을 사용합니다. 파이썬 프로그래머의 경우.

  • pybind11 (그리고 boost.python)은 반대입니다. C ++ 측에서 컴파일 시간에 물건을 바인딩하십시오. C ++ 프로그래머의 경우.

  • CFFI 런타임에 기본 재료를 동적으로 바인딩 할 수 있습니다. 사용하기 간단하지만 성능이 높아집니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top