Frage

Ich fand den Flaschenhals in meinem python-code, spielte mit psycho etc.Dann beschlossen, schreiben Sie eine c/c++ - Erweiterung für die Leistung.

Mit Hilfe von swig Sie fast nicht brauchen, um über Argumente etc.Alles funktioniert einwandfrei.

Nun meine Frage:Schluck schafft ein ganz großes py-Datei, die eine Menge macht 'checkings' und 'PySwigObject' vor dem Aufruf der eigentlichen .pyd oder .also code.

Hat jemand von Euch Erfahrung, ob es ist etwas mehr Leistung zu gewinnen, wenn Sie von hand schreiben dies Datei oder lassen Sie Schluck es tun.

War es hilfreich?

Lösung

Für sicher, Sie werden immer eine Leistungssteigerung haben dies von Hand tun, aber der Gewinn wird sehr klein im Vergleich zu dem Aufwand, dies zu tun. Ich habe keine Figur haben Sie zu geben, aber ich nicht empfehlen, weil Sie die Schnittstelle von Hand müssen halten, und dies ist keine Option, wenn Ihr Modul groß ist!

Sie haben das Richtige getan wählte eine Skriptsprache zu verwenden, da Sie schnelle Entwicklung wollten. Auf diese Weise haben Sie die frühe Optimierung Syndrom vermieden, und jetzt wollen Sie Engpass Teile optimieren, großartig! Aber wenn Sie die C / Python-Schnittstelle von Hand tun, werden Sie in der frühen Optimierung Syndrom sicher fallen.

Wenn Sie etwas mit weniger Interface-Code mögen, können Sie darüber nachdenken, eine DLL-Datei von Ihrem C-Code erstellen, und verwenden Sie diese Bibliothek direkt aus Python mit cstruct .

Beachten Sie auch Cython wenn Sie Python-Code in Ihrem Programm verwenden möchten.

Andere Tipps

Sollten Sie betrachten, Steigern.Python wenn Sie sind nicht Planung zu generieren bindings für andere Sprachen sowie mit swig.

Wenn Sie haben eine Menge von Funktionen und Klassen zu binden, Py++ ist ein tolles tool, das automatisch generiert den erforderlichen code, um die Bindungen.

Pybindgen kann auch eine option sein, aber es ist ein neues Projekt und weniger vollständig, dass Boost.Python.


Edit:

Vielleicht brauche ich mehr explizit über vor-und Nachteile.

  • Swig:

    pro:Sie können generieren-Bindungen für zahlreiche Skriptsprachen.

    Nachteile:Ich weiß nicht, wie der parser funktioniert.Ich weiß nicht, ob das machte einige Fortschritte, aber vor zwei Jahren die C++ - parser, Recht begrenzt.Die meisten der Zeit, die ich hatte, um zu kopieren/Vergangenheit meine .h Header hinzufügen einige % Zeichen und geben zusätzliche Hinweise auf die Schluck-parser.

    Ich war auch notwendig, um die Python-C-API von Zeit zu Zeit für (nicht so) kompliziert, Typ-Konvertierungen.

    Ich bin nicht mehr verwendet wird.

  • Boost.Python:

    pro:Es ist eine sehr umfassende Bibliothek.Es ermöglicht Sie zu tun fast alles, was möglich ist mit der C-API verwenden, aber in C++.Ich hatte nie zu schreiben, C-API-code mit dieser Bibliothek.Ich habe auch nie aufgetretene Fehler durch die Bibliothek.Code für Bindungen entweder funktioniert wie ein Charme oder sich weigern, Sie zu kompilieren.

    Es ist wahrscheinlich eine der besten Lösungen, die derzeit verfügbar, wenn Sie bereits einige C++ - Bibliothek zu binden.Aber wenn Sie nur eine kleine C-Funktion neu zu schreiben, würde ich wahrscheinlich versuchen, mit Cython.

    Nachteile:wenn Sie nicht haben eine vorkompilierte Boost.Python-Bibliothek, die Sie Bjam (Art Ersatz).Ich hasse Bjam und seine syntax.

    Python-Bibliotheken erstellt mit dem B. P neigen zu Fettleibigkeit.Es dauert auch eine Menge von Zeit zu kompilieren.

  • Py++ (abgekündigt):es ist zu Steigern.Python leicht gemacht.Py++ verwendet einen C++ - parser zum Lesen von code und generiert dann Steigern.Python-code automatisch.Sie haben auch eine große Unterstützung von seinem Autor (Nein, es ist nicht von mir ;-) ).

    Nachteile:nur die Probleme aufgrund zu Steigern.Python selbst.Update:Als 2014 das Projekt sieht nun eingestellt.

  • Pybindgen:

    Es erzeugt den code, Umgang mit der C-API.Sie können entweder beschreiben, - Funktionen und-Klassen, die in einer Python-Datei, oder lassen Sie Pybindgen Lesen Sie Ihre Kopf-und generieren Bindungen automatisch (für das es verwendet pygccxml, eine python-Bibliothek, geschrieben vom Autor von Py++).

    Nachteile:es ist ein junges Projekt, mit einem kleineren team als Boost.Python.Es gibt immer noch einige Einschränkungen:Sie können nicht mehrere Vererbung für Ihre C++ - Klassen, Rückrufe (nicht automatisch, benutzerdefinierte callback-handling-code geschrieben werden kann, obwohl).Übersetzung von Python-Ausnahmen von C.

    Es lohnt sich auf jeden Fall einen guten Blick.

  • Neu:Auf 2009/01/20 der Autor von Py++ angekündigt neue Paket für die Anbindung von C/C++ - code in python.Es basiert auf ctypes.Ich habe nicht versucht es bereits, aber ich will!Hinweis:dieses Projekt sieht discontiued, als Py++.

  • CFFI:Ich wusste nicht, die Existenz dieses einen, bis vor kurzem so jetzt kann ich nicht geben meiner Meinung nach.Es sieht aus wie Sie definieren können C-Funktionen in Python-strings und rufen Sie Sie direkt aus der gleichen Python-Modul.

  • Cython:Dies ist die Methode, die ich verwende in meinen Projekten.Im Grunde kannst du code schreiben, der im besonderen .pyx-Dateien.Diese Dateien kompiliert (übersetzt) in C-code, die wiederum kompiliert werden CPython-Module.Cython-code Aussehen können wie die normalen Python (und in der Tat reines Python gültig sind .pyx Cython-Dateien), aber Sie können auch mehr Informationen wie Variablen-Typen.Diese optionale Eingabe erlaubt Cython zu erzeugen schnellere C-code.Code in Cython Dateien aufrufen können sowohl Reine Python-Funktionen, aber auch C und C++ Funktionen (und auch C++ - Methoden).

    Es dauerte einige Zeit, um zu denken, in Cython, dass in den gleichen code Aufruf von C-und C++ - Funktion, mix-Python-und C-Variablen, und so weiter.Aber es ist eine sehr mächtige Sprache, mit einer aktiven (im Jahr 2014) und freundlichen community.

SWIG 2.0.4 hat eine neue -builtin Option eingeführt, die die Leistung verbessert. Ich habe einige Benchmarking ein Beispiel-Programm, das viel schneller Anrufe an eine C ++ Erweiterung tut. Ich baute die Erweiterung mit boost.python, PyBindGen, SIP und SWIG mit und ohne -builtin Option. Hier sind die Ergebnisse (durchschnittlich 100 Läufe):

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

SWIG verwendet langsamste zu sein. Mit der neuen Option -builtin scheint SWIG schnellste zu sein.

Mit Cython ist ziemlich gut. Sie können Ihre C-Erweiterung mit einem Python-ähnliche Syntax schreiben und haben es C-Code generieren. Vorformulierten enthalten. Da Sie den Code bereits in Python haben, müssen Sie nur ein paar Änderungen an der Engpass-Code und C-Code tun, wird daraus erstellt werden.

Beispiel. hello.pyx:

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

Das erzeugt 601 Zeilen Standardcode:

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

Eine Beobachtung: Basierend auf dem Benchmarking von dem pybindgen Entwickler durchgeführt, gibt es keinen signifikanten Unterschied zwischen boost.python und säuft. Ich habe nicht mein eigenes Benchmarking durchgeführt, um zu überprüfen, wie viel von diesem hängt von der korrekten Verwendung der boost.python Funktionalität.

Beachten Sie auch, dass es einen Grund sein kann, dass pybindgen im Allgemeinen ziemlich viel schneller zu sein scheint als swig und boost.python: es können nicht so vielseitig produzieren wie die beiden anderen eine Bindung. Zum Beispiel Ausnahme Ausbreitung, Anruf Argument Typprüfung, etc. Ich habe keine Chance zu nutzen pybindgen noch hatte, aber ich beabsichtige zu.

Boost ist im Allgemeinen ziemlich großes Paket zu installieren, und letzte, was ich sehe, Sie können nicht nur boost Python installieren Sie so ziemlich die ganze Boost-Bibliothek benötigen. Wie andere erwähnt haben Kompilierung wird langsam sein, aufgrund der starken Nutzung der Template-Programmierung, die auch in der Regel eher kryptische Fehlermeldungen bei der Kompilierung bedeutet.

Zusammenfassung: gegeben, wie einfach SWIG zu installieren und zu verwenden, dass es anständig erzeugt Bindung, die robust und vielseitig einsetzbar ist, und dass eine Schnittstellendatei C ++ DLL erlaubt aus mehreren anderen Sprachen wie LUA, C # zur Verfügung zu stehen, und Java, ich würde es über boost.python begünstigen. Aber wenn Sie wirklich mehrsprachige Unterstützung benötigen würde ich einen Blick auf PyBindGen nimmt wegen seiner vorgeblichen Geschwindigkeit und achte auf Robustheit und Vielseitigkeit der Bindung erzeugt sie.

Da Sie Geschwindigkeit und Overhead betroffen sind, schlage ich vor, unter Berücksichtigung PyBindGen .

Ich habe Erfahrung mit ihm einer großen internen C ++ Bibliothek wickeln. Nach dem Versuch, SWIG, SIP, und Boost.Python Ich ziehe PyBindGen aus den folgenden Gründen:

  1. Ein PyBindGen Wrapper ist pure-Python, keine Notwendigkeit, ein anderes Dateiformat
  2. lernen
  3. PyBindGen erzeugt Python C API direkt aufruft, gibt es keine Drehzahl raubt-Indirektion Schicht wie SWIG.
  4. Der generierte C-Code ist sauber und einfach zu verstehen. Ich mag Cython auch, aber versucht, seine C-Ausgabe lesen kann manchmal schwierig sein.
  5. STL-Sequenz-Container unterstützt werden (wir verwenden eine Menge std :: Vektors)

Es Drachen hier sein. Nicht swig, steigert nicht. Für jedes komplizierte Projekt, das Sie den Code haben an sich selbst füllen sie Arbeit wird unkontrollierbar schnell zu machen. Wenn es ein einfacher C-API in Ihrer Bibliothek (kein Unterricht) ist, können Sie einfach ctypes verwenden. Es ist einfach und schmerzlos, und Sie werden nicht Stunden damit verbringen, haben Sie in der Dokumentation Schleppen durch für diese labyrinthischen Wrapper Projekte versuchen zu finden, die eine kleine Notiz über die Funktion, die Sie benötigen.

Wenn es nicht eine große Erweiterung, boost :: Python könnte auch eine Option sein, es wird schneller ausgeführt als swig, weil Sie kontrollieren, was passiert ist, aber es wird länger dauern, bis dev.

Anyways swig Overhead ist akzeptabel, wenn die Menge der Arbeit in einem einzigen Anruf groß genug ist. Zum Beispiel, wenn Sie Problem ist, dass Sie einige mittelgroße Logikblock haben Sie zu C / C verschieben möchten ++, aber das Block innerhalb einer engen Schleife genannt, häufig, haben Sie vielleicht swig zu vermeiden, aber ich kann nicht wirklich denken jeder reale Beispiele mit Ausnahme scripted Grafiken Shadern.

Vor dem Python-Code Aufgeben, einen Blick auf ShedSkin . Sie behaupten, eine bessere Leistung als Psyco auf einigen Code (und auch feststellen, dass es noch experimentell).

Else, gibt es mehrere Möglichkeiten für die Bindung von C / C ++ Code zu Python.

Boost ist langwierig zu kompilieren, ist aber wirklich die flexible und einfache Lösung zu verwenden.

Ich habe SWIG nie verwendet, aber im Vergleich zu steigern, ist es nicht so flexibel, wie es generischer verbindlicher Rahmen ist, kein Rahmen Python gewidmet ist.

Als nächstes Wahl Pyrex . Es ermöglicht den Pseudo-Python-Code zu schreiben, der als C-Erweiterung kompiliert wird.

Es gibt einen Artikel wert zum Thema lesen

scroll top