python 확장 - swig 또는 Cython이 아닌 swig로 확장
사이코랑 놀아난 내 비단뱀 코드에서 병목현상을 발견했어그 후 퍼포먼스를 위해 c/c++ 확장자를 쓰기로 했습니다.
스위크의 도움으로 당신은 논쟁 등에 거의 신경 쓸 필요가 없다.모든 것이 잘 작동한다.
이제 질문하겠습니다. swig는 실제 .pyd 또는 .so 코드를 호출하기 전에 많은 '체크'와 'PySwigObject'를 수행하는 상당히 큰 py 파일을 만듭니다.
이 파일을 손으로 쓰거나 swig에게 맡기면 성능이 향상될지 경험해 본 사람이 있습니까?
Boost를 고려해야 합니다.다른 언어에 대한 바인딩을 생성하지 않을 계획인 경우 Python을 참조하십시오.
바인딩할 함수와 클래스가 많은 경우 Py++는 바인딩을 만드는 데 필요한 코드를 자동으로 생성하는 훌륭한 도구입니다.
Pybindgen도 선택사항이 될 수 있지만, 이것은 새로운 프로젝트이며 Boost의 완성도는 낮습니다.파이썬.
편집:
찬반 양론에 대해 좀 더 명확하게 말할 필요가 있을 것 같아요.
스위그:
pro: 많은 스크립트 언어의 바인딩을 생성할 수 있습니다.
단점: 파서가 작동하는 방식이 마음에 들지 않습니다.진척이 있었는지 모르겠지만 2년 전만 해도 C++ 파서는 상당히 제한적이었습니다. 했습니다.h 헤더를 몇 개 추가합니다.
%
parser.swig에 .복잡한 타입의 변환(그렇지 않음)을 위해 Python C-API를 수시로 처리해야 했습니다.
더 이상 사용하지 않아요.
Boost.Python:
pro: 매우 완전한 라이브러리입니다.C-API에서 가능한 거의 모든 작업을 C++에서 수행할 수 있습니다.나는 이 라이브러리에서 C-API 코드를 쓸 필요가 없었다.저도 도서관 때문에 버그를 본 적이 없어요.바인딩 코드는 부적처럼 작동하거나 컴파일을 거부합니다.
바인드하는 C++ 라이브러리가 이미 있는 경우 현재 사용 가능한 최고의 솔루션 중 하나일 수 있습니다.하지만 만약 당신이 다시 쓰는 작은 C 함수만 있다면, 나는 Cython을 사용해 볼 것입니다.
단점: 사전 컴파일된 Boost가 없는 경우.Python 라이브러리는 Bjam(일종의 대체품)을 사용합니다.나는 짬과 그 구문이 정말 싫다.
B로 작성된 Python 라이브러리.P는 비만이 되는 경향이 있다.컴파일하는 데도 시간이 많이 걸립니다.
Py++(단종): Boost입니다.Python은 쉽게 만들었습니다.Py++는 C++ 파서를 사용하여 코드를 읽은 후 Boost를 생성합니다.Python은 자동으로 코드됩니다.당신은 그 책의 저자로부터도 큰 지지를 받고 있습니다(아니에요;-).
단점: Boost로 인한 문제만 있습니다.Python 그 자체.업데이트:2014년 현재 이 프로젝트는 중단된 것으로 보입니다.
파이빈드겐:
C-API를 다루는 코드를 생성합니다.함수 및 클래스를 Python 파일로 기술하거나 Pybindgen이 헤더를 읽고 바인딩을 자동으로 생성하도록 할 수 있습니다(이를 위해 Py++의 작성자가 작성한 Python 라이브러리인 pygccml을 사용합니다).
단점: Boost보다 적은 수의 팀을 가진 젊은 프로젝트입니다.Python. 아직 몇 가지 제한이 있습니다. C++ 클래스인 콜백에 다중 상속을 사용할 수 없습니다(단, 자동으로 콜백 처리 코드를 작성할 수는 없습니다).Python 예외를 C로 변환합니다.
그것은 확실히 잘 볼 가치가 있다.
새로운 것: 2009/01/20에 Py++의 작성자는 C/C++ 코드를 파이썬과 인터페이스하기 위한 새로운 패키지를 발표했습니다.ctype을 기반으로 합니다.아직 안 해봤는데 먹어볼게요.주의: 이 프로젝트는 Py++로 불만족스러워 보입니다.
CFFI: 나는 매우 최근까지 이것의 존재를 몰랐기 때문에 지금으로서는 내 의견을 말할 수 없다.Python 문자열에 C 함수를 정의하고 동일한 Python 모듈에서 직접 호출할 수 있습니다.
이것이 제가 현재 프로젝트에서 사용하고 있는 방법입니다.기본적으로 특수 .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는 성능을 향상시키는 새로운 내장 옵션을 도입했습니다.C++ 내선 번호로 고속 콜을 많이 하는 예제 프로그램을 사용하여 벤치마킹을 실시했습니다.나는 부스트를 사용해서 증축을 했다.-builtin 옵션 유무에 관계없이 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, pybind11, cffi 토픽에 대해 읽을 만한 기사가 있습니다. 어떤 도구를 선택해야 합니까?
성급한 분들을 위한 간단한 요약:
Cython은 당신의 python을 C/C++로 컴파일하여 C/C++를 python 코드에 삽입할 수 있도록 합니다.스태틱 바인딩을 사용합니다.python 프로그래머용.
pybind11(및 부스트).python)은 그 반대입니다.컴파일 시에 C++측에서 바인드 합니다.C++ 프로그래머용.
CFFI를 사용하면 런타임에 네이티브 파일을 동적으로 바인딩할 수 있습니다.사용법은 간단하지만 퍼포먼스가 저하됩니다.
물론, 이 작업을 수작업으로 하면 항상 퍼포먼스가 향상되지만, 이 작업에 필요한 노력에 비하면 그 효과는 매우 작습니다.수치는 알 수 없지만 인터페이스를 수동으로 유지해야 하기 때문에 권장하지 않습니다.모듈이 크면 이 옵션이 아닙니다.
신속한 개발을 원했기 때문에 스크립트 언어를 선택한 것은 올바른 선택이었습니다.이렇게 하면 초기 최적화 증후군을 피할 수 있었고, 이제는 병목 부분을 최적화하려고 합니다. 대단합니다!그러나 C/피톤 인터페이스를 손으로 하면 초기 최적화 증후군에 빠질 것이 확실합니다.
인터페이스 코드가 적은 것을 원한다면 C 코드에서 dll을 생성하고 cstruct를 사용하여 python에서 직접 라이브러리를 사용할 수 있습니다.
프로그램에서 python 코드만 사용하고 싶다면 Cython도 고려해보세요.
여기 용이 있어요.꿀꺽꿀꺽하지 말고, 부풀리지 마.복잡한 프로젝트에서는 코드를 직접 입력해 작업을 진행해야 합니다.이 코드를 빠르게 관리할 수 없게 됩니다.라이브러리에 대한 일반 C API(클래스 없음)인 경우 ctype만 사용할 수 있습니다.이 기능은 쉽고 쉽게 사용할 수 있습니다.또, 이러한 미로 같은 래퍼 프로젝트의 메뉴얼을 몇시간이나 더듬어, 필요한 기능에 관한 작은 메모를 찾아낼 필요가 없습니다.
관찰: Pybindgen 개발자가 실시한 벤치마킹에 따르면 Boost 간에 큰 차이는 없다.파이톤과 스위그.이 중 어느 정도가 부스트의 적절한 사용에 좌우되는지를 검증하기 위한 자체 벤치마킹은 실시하지 않았습니다.python 기능.
또한 일반적으로 pybindgen이 swig 및 boost보다 상당히 빠른 것으로 보이는 이유가 있을 수 있습니다.python: 다른 두 가지만큼 다양한 바인딩을 생성하지 못할 수 있습니다.예를 들어 예외 전파, 콜 인수 유형 확인 등입니다.아직 피빈드겐을 써본 적은 없지만 써보려고 합니다.
Boost는 일반적으로 설치하기에 꽤 큰 패키지입니다.그리고 마지막으로 본 바로는 Boost python을 설치할 수 없다는 것을 알았습니다.Boost 라이브러리 전체가 매우 필요합니다.다른 사람들이 언급했듯이 템플릿프로그래밍을 많이 사용하기 때문에 컴파일이 느려집니다.이것은 컴파일 시 일반적으로 다소 알기 어려운 에러 메시지를 의미합니다.
개요: SWIG의 설치와 사용이 얼마나 쉬운지, 견고하고 다용도적인 바인딩을 생성하며, 1개의 인터페이스 파일로 LUA, C#, Java 등의 다른 여러 언어에서 C++ DLL을 사용할 수 있다는 점을 고려하면 부스트보다 더 선호합니다.PyBindGen은 다언어 지원이 꼭 필요한 경우가 아니라면 속도 때문에 PyBindGen을 자세히 살펴보고 바인딩의 견고성과 다양성에 주의를 기울이겠습니다.
Cython을 사용하는 것은 꽤 좋습니다.Python과 같은 구문을 사용하여 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을 검토하시기 바랍니다.
큰 내부 C++ 라이브러리를 포장할 때 사용한 경험이 있습니다.SWIG, SIP, Boost를 시도하면.PyBindGen을 선호하는 이유는 다음과 같습니다.
- PyBindGen 래퍼는 순수 Python이므로 다른 파일 형식을 배울 필요가 없습니다.
- PyBindGen은 Python C API 호출을 직접 생성하며 SWIG와 같은 속도 강탈 간접 계층은 없습니다.
- 생성된 C 코드는 깨끗하고 이해하기 쉽습니다.저도 Cython을 좋아하지만 C 출력을 읽기가 어려울 수 있습니다.
- STL 시퀀스 컨테이너가 지원됩니다(std::벡터의 용어가 많이 사용됨).
큰 확장이 아닌 경우 boost::python도 옵션일 수 있습니다.스위그보다 실행 속도가 빠릅니다.왜냐하면 상황을 제어할 수 있기 때문입니다만, 개발에는 시간이 걸립니다.
어쨌든, 1회의 콜내의 작업량이 충분한 경우, SWIG의 오버헤드는 허용됩니다.예를 들어 C/C++로 이행하고 싶은 중간 크기의 논리 블록이 있는 경우, 그 블록은 좁은 루프 내에서 호출됩니다.흔히 swig를 피해야 하지만 스크립트에 사용되는 그래픽 셰이더 이외에는 실제의 예를 생각할 수 없습니다.
Python 코드를 포기하기 전에 SheetSkin을 살펴보세요.그들은 일부 코드에서 싸이코보다 더 나은 성능을 자랑한다.
또는 C/C++ 코드를 python에 바인드하기 위한 몇 가지 선택지가 있습니다.
Boost는 컴파일하는 데 시간이 오래 걸리지만 가장 유연하고 사용하기 쉬운 솔루션입니다.
SWIG를 사용한 적은 없지만 boost와 비교하면 python 전용 프레임워크가 아닌 범용 바인딩 프레임워크만큼 유연하지 않습니다.
다음 선택은 파이렉스입니다.C 확장자로 컴파일되는 의사 python 코드를 쓸 수 있습니다.
언급URL : https://stackoverflow.com/questions/456884/extending-python-to-swig-not-to-swig-or-cython
'source' 카테고리의 다른 글
소품 및 데이터 중복을 방지하려면 어떻게 해야 합니까? (0) | 2022.09.03 |
---|---|
Java에서의 정적 할당 - 힙, 스택 및 영구 생성 (0) | 2022.09.03 |
javascript에서 . (dot)를 숫자와 연결하는 방법 (0) | 2022.09.01 |
Vue 구성 요소를 테스트할 때 측면 플러그인을 시뮬레이션하는 방법 (0) | 2022.09.01 |
모듈 저장소가 상태로 재설정됨 (0) | 2022.09.01 |