Pergunta

Eu encontrei o gargalo no meu código python, brinquei com psico etc. Então decidi escrever a / c ++ extensão c para o desempenho.

Com a ajuda de gole você quase não precisa se preocupar com argumentos etc. Tudo bem funciona.

Agora a minha pergunta:. Gole cria uma bastante grande py-arquivo, que faz um monte de 'verificações' e 'PySwigObject' antes de chamar o .pyd real ou .so código

Alguém de vocês tem alguma experiência se há mais algum desempenho a ganhar se você mão-escrever este arquivo ou deixar gole fazê-lo.

Foi útil?

Solução

Com certeza você sempre terá um ganho de desempenho fazendo isso com a mão, mas o ganho será muito pequeno em comparação com o esforço necessário para fazer isso. Eu não tenho qualquer figura para lhe dar, mas eu não recomendo este, porque você vai precisar para manter a interface com a mão, e isso não é uma opção se o seu módulo é grande!

Você fez a coisa certa ao optar por usar uma linguagem de script porque você queria um rápido desenvolvimento. Desta forma, você evitou a síndrome otimização cedo, e agora você quer otimizar peças do gargalo, ótimo! Mas se você fizer a interface C / python à mão você vai cair na síndrome otimização início, com certeza.

Se você quiser algo com código menos interface, você pode pensar em criar uma dll do seu código C, e usar essa biblioteca diretamente do python com cstruct .

Considere também Cython se você quiser usar apenas o código python em seu programa.

Outras dicas

Você deve considerar Boost.Python se você não está planejando para gerar ligações para outras línguas, bem como com gole.

Se você tem um monte de funções e classes para bind, Py ++ é uma grande ferramenta que automaticamente gera o código necessário para fazer as ligações.

Pybindgen também pode ser uma opção, mas é um novo projeto e menos completa que aumentam .Python.


Editar:

Talvez eu preciso ser mais explícito sobre prós e contras.

  • Swig:

    pro:. Você pode gerar ligações para muitas linguagens de script

    contras: não Eu gosto da forma como o analisador funciona. Eu não sei se o fez algum progresso, mas há dois anos o C ++ analisador foi bastante limitado. Na maioria das vezes eu tinha que copiar / passado meus cabeçalhos .h adicionar alguns caracteres % e dar dicas extras para o analisador gole.

    Eu também era necessário para lidar com o Python C-API de tempos em tempos para (não tão) conversões de tipo complicadas.

    Eu não estou usando isso.

  • Boost.Python:

    pro: É uma biblioteca muito completa. Ele permite que você fazer quase tudo o que é possível com o C-API, mas em C ++. Eu nunca tive que escrever código C-API com esta biblioteca. Eu também nunca encontrou bug devido à biblioteca. Código para ligações tanto funciona como um encanto ou recusar compilação.

    É provavelmente uma das melhores soluções actualmente disponíveis se você já tem alguma biblioteca C ++ para bind. Mas se você só tem uma função pequena C para reescrever, eu provavelmente iria tentar com Cython.

    contras: se você não tem uma biblioteca pré-compilada Boost.Python você vai usar bjam (espécie de substituição make). Eu realmente odeio bjam e sua sintaxe.

    bibliotecas Python criados com p.e tendem a ficar obesos. Ele também leva um muito de tempo para compilá-los.

  • Py ++ (descontinuado): é Boost.Python fácil. Py ++ usa o analisador de um C ++ para ler o código e, em seguida, gera código Boost.Python automaticamente. Você também tem um grande apoio do seu autor (não, não é me ;-)).

    contras: apenas os problemas devido à própria Boost.Python. Update:. A partir de 2014 este projecto parece agora descontinuado

  • Pybindgen:

    Ele gera o tráfico de código com o C-API. Você pode descrever funções e classes em um arquivo de Python, ou deixar Pybindgen ler seus cabeçalhos e gerar ligações automaticamente (por isso ele usa pygccxml, uma biblioteca python escreveu pelo autor do Py ++).

    contras: é um projeto jovem, com uma equipe menor do que Boost.Python. Existem ainda algumas limitações: você não pode usar herança múltipla para as classes C ++, chamadas de retorno (não automaticamente, costume código de tratamento de retorno de chamada pode ser escrito, embora). Tradução de exceções Python para C.

    É definitivamente uma boa olhada.

  • Um novo: Em 2009/01/20 o autor de Py ++ anunciou um novo pacote de interface de código C / C ++ com o pitão. É baseado em ctypes. Eu não experimentá-lo já, mas eu vou! Nota: olha esse projeto discontiued, como Py ++

  • .
  • CFFI : Eu não sabia que a existência de um presente até muito recentemente então por enquanto eu não posso dar minha opinião. Parece que você pode definir funções C em strings em Python e chamá-los diretamente a partir do mesmo módulo Python.

  • Cython : Este é o método que eu estou usando atualmente em meus projetos. Basicamente você escrever código em arquivos .pyx especiais. Esses ficheiros são compilados (traduzida) em código C, que por sua vez são compilados para módulos CPython. código Cython pode olhar como Python normal (e, na verdade pura Python são arquivos .pyx Cython válidos), mas você pode umlso mais informações como tipos de variáveis. Este digitação opcional permite Cython para gerar código C mais rápido. Código em arquivos Cython pode chamar ambas funções puras Python, mas também funções C e C ++ (e também métodos de C ++).

    Levei algum tempo para pensar em Cython, que, na mesma chamada em código C e função C ++, misture variáveis ??em Python e C, e assim por diante. Mas é uma linguagem muito poderosa, com um ativo (em 2014) e comunidade amigável.

SWIG 2.0.4 introduziu uma nova opção -builtin que melhora o desempenho. Eu fiz alguma análise comparativa usando um exemplo de programa que faz um monte de chamadas rápidas para uma extensão de C ++. Eu construí a extensão usando boost.python, PyBindGen, SIP e SWIG com e sem a opção -builtin. Aqui estão os resultados (média de 100 corridas):

SWIG with -builtin     2.67s
SIP                    2.70s
PyBindGen              2.74s
boost.python           3.07s
SWIG without -builtin  4.65s

SWIG costumava ser mais lento. Com a nova opção -builtin, SWIG parece ser mais rápido.

Usando Cython é muito bom. Você pode escrever o seu ramal C com uma sintaxe Python-like e tê-lo gerar o código C. Clichê incluído. Desde que você tem o código já em python, você tem que fazer apenas algumas alterações em seu código de gargalo e de código C será gerado a partir dele.

Exemplo. hello.pyx:

cdef int hello(int a, int b):
    return a + b

Isso gera 601 linhas de código clichê:

/* 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);
    }
}

Uma observação: Com base na avaliação comparativa realizado pelos desenvolvedores pybindgen, não há diferença significativa entre boost.python e gole. Eu não tenho feito minha própria avaliação comparativa para verificar o quanto isso depende do uso adequado da funcionalidade boost.python.

Note-se também que pode haver uma razão que pybindgen parece ser, em geral, um pouco mais rápido do que gole e boost.python: é pode não produzem tão versátil uma ligação como os outros dois. Por exemplo, a propagação de exceção, argumento de chamada verificação de tipo, etc. eu não tive a chance de usar pybindgen ainda, mas eu pretendo.

Boost é em geral pacote muito grande para instalar e última vez que vi você não pode simplesmente instalar o impulso python você praticamente necessidade toda a biblioteca Boost. Como já foi mencionado compilação será lento devido ao uso pesado de programação modelo, o que significa também mensagens de erro normalmente bastante enigmáticas em tempo de compilação.

Resumo: dado o quão fácil SWIG é de instalar e usar, que gera decente ligação que é robusto e versátil, e que um arquivo de interface permite que o C ++ DLL para estar disponível a partir de várias outras linguagens como LUA, C # e Java, Eu iria favorecê-lo sobre boost.python. Mas a menos que você realmente precisa de apoio multi-linguagem que eu levaria um olhar mais atento sobre PyBindGen devido à sua velocidade suposto, e prestar muita atenção à robustez e versatilidade de ligação que gera.

Uma vez que você está preocupado com a velocidade e sobrecarga, sugiro considerando PyBindGen .

Eu tenho experiência de usá-lo para embrulhar uma grande biblioteca interna C ++. Depois de tentar SWIG, SIP, e Boost.Python prefiro PyBindGen pelos seguintes motivos:

  1. A PyBindGen invólucro é puro-Python, não há necessidade de aprender outro formato de arquivo
  2. PyBindGen gera Python C API chamadas diretamente, não há nenhuma camada de indireção-roubando velocidade como SWIG.
  3. O código C gerado é limpo e simples de entender. I como Cython também, mas tentando ler sua saída C pode ser difícil às vezes.
  4. recipientes seqüência STL são suportados (usamos um monte de std :: vector de)

There Be Dragons aqui. Não gole, não aumentar. Para qualquer projeto complicado o código você tem que preencher em si mesmo para torná-los trabalho torna-se incontrolável rapidamente. Se for um C API simples para a sua biblioteca (sem classes), você pode simplesmente usar ctypes. Vai ser fácil e indolor, e você não terá que passar horas arrasto através da documentação para estes labiríntica invólucro projectos tentando encontrar o caminho pequena nota sobre o recurso que você precisa.

Se não é um grande extensão, boost :: python também pode ser uma opção, ele executa mais rápido do que gole, porque você controla o que está acontecendo, mas vai demorar mais tempo para desenv.

sobrecarga

De qualquer forma do gole é aceitável se a quantidade de trabalho dentro de uma única chamada é grande o suficiente. Por exemplo, se você questão é que você tem algum tamanho bloco lógico meio que você deseja mover para C / C ++, mas esse bloco é chamado dentro de um apertado-loop, com freqüência, você pode ter que gole evitar, mas eu realmente não posso pensar de qualquer exemplos do mundo real, exceto para shaders gráficos script.

Antes de desistir de seu código python, ter um olhar para ShedSkin . Eles afirmam desempenho melhor do que Psyco em algum código (e também afirmam que ainda é experimental).

Else, existem várias opções para ligação de código C / C ++ para python.

Boost é demorado para compilar, mas é realmente o mais flexível e fácil de usar solução.

Eu nunca usei SWIG mas em comparação com impulso, não é tão flexível como é quadro vinculativo genérico, não uma estrutura dedicada a python.

A seguir escolha é Pyrex . Ele permite ao código python gravação pseudo que é compilado como uma extensão C.

Há um artigo vale a pena ler sobre o tema Cython, pybind11, CFFI - qual ferramenta você deve escolher

?

rápida recapitulação para os impacientes:

  • Cython compila seu python para C / C ++ que lhe permite incorporar o seu C / C ++ em código python. Usos vinculação estática. Para programadores python.

  • pybind11 (e boost.python) é o oposto. Bind suas coisas em tempo de compilação do lado do C ++. Para programadores C ++.

  • CFFI permite-lhe ligar o material nativo dinamicamente durante a execução. Simples de usar, mas maior penalidade de desempenho.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top