Python: SWIG vs ctypes


En python, ¿bajo qué circunstancias SWIG es una mejor opción que ctypes para llamar a puntos de entrada en bibliotecas compartidas? Supongamos que aún no tiene los archivos de interfaz SWIG.

¿cuáles son las métricas de rendimiento de los dos?

Author: David Nehme, 2008-09-26

10 answers

SWIG genera (bastante feo) código C o C++. Es fácil de usar para funciones simples (cosas que se pueden traducir directamente) y razonablemente fácil de usar para funciones más complejas (como funciones con parámetros de salida que necesitan un paso de traducción adicional para representar en Python.) Para una interfaz más potente, a menudo necesita escribir bits de C como parte del archivo de interfaz. Para cualquier cosa que no sea un uso simple, necesitará saber sobre CPython y cómo representa los objetos not no difícil, pero algo a tener en cuenta.

Ctypes le permite acceder directamente a funciones de C, estructuras y otros datos, y cargar bibliotecas compartidas arbitrarias. No necesita escribir ninguna C para esto,pero necesita entender cómo funciona C. Es, se podría argumentar, la otra cara de SWIG: no genera código y no requiere un compilador en tiempo de ejecución, pero para cualquier cosa que no sea simple, requiere que entienda cómo cosas como tipos de datos de C, casting, administración de memoria y trabajo de alineación. También necesita traducir de forma manual o automática estructuras C, uniones y matrices en la estructura de datos ctypes equivalente, incluido el diseño de memoria correcto.

Es probable que en la ejecución pura, SWIG sea más rápido que ctypes because porque la administración alrededor del trabajo real se realiza en C en tiempo de compilación en lugar de en Python en tiempo de ejecución. Sin embargo, a menos que interfieras con muchas funciones de C diferentes, pero cada una solo unas pocas veces, es poco probable que la sobrecarga sea realmente notable.

En tiempo de desarrollo, ctypes tiene un costo de inicio mucho menor: no tiene que aprender sobre los archivos de interfaz, no tiene que generar .c archivos y compilarlos, usted no tiene que comprobar y silenciar las advertencias. Puede simplemente saltar y comenzar a usar una sola función de C con un esfuerzo mínimo, luego expandirla a más. Y tienes la oportunidad de probar y probar las cosas directamente en el intérprete de Python. Envolver mucho código es algo tedioso, aunque hay intentos de hacerlo más simple (como ctypes-configure.)

SWIG, por otro lado, se puede usar para generar envoltorios para múltiples idiomas (excepto los detalles específicos del idioma que deben completarse, como el código C personalizado que mencioné anteriormente.) Al empaquetar montones y montones de código que SWIG puede manejar con poca ayuda, la generación de código también puede ser mucho más sencilla de configurar que los equivalentes de ctypes.

 60
Author: Thomas Wouters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 20:47:28

Tengo una rica experiencia de usar swig. SWIG afirma que es una solución rápida para envolver cosas. Pero en la vida real...


Contras:

SWIG está desarrollado para ser general, para todos y para más de 20 idiomas. Generalmente conduce a inconvenientes:
- necesita configuración (SWIG .i plantillas), a veces es complicado,
- la falta de tratamiento de algunos casos especiales (ver propiedades de python más adelante),
- falta de rendimiento para algunos idiomas.

Python contras:

1) Inconsistencia de estilo de código . C++ y python tienen estilos de código muy diferentes (eso es obvio, ciertamente), las posibilidades de swig de hacer que el código de destino sea más pitónico son muy limitadas. Como ejemplo, es butt-heart para crear propiedades de getters y setters. Ver este q & a

2) Falta de comunidad amplia . Swig tiene buena documentación. Pero si uno atrapó algo que no está en la documentación, no hay información en absoluto. No hay blogs ni google ayuda. Así que uno tiene que cavar fuertemente código generado SWIG en tales casos... Eso es terrible, podría decir...

Procs:

  • En casos simples es realmente rápido, fácil y directo

  • Si produjo archivos de interfaz swig una vez, puede envolver este código C++ en CUALQUIERA de los otros 20 idiomas (!!!).

  • Una gran preocupación sobre SWIG es una actuación. Desde la versión 2.04 SWIG incluye' - builtin ' bandera que hace SWIG incluso más rápido que otras formas automatizadas de envolver. Al menos algunos puntos de referencia muestran esto.


¿Cuándo USAR SWIG?

Así que concluí para mí dos casos cuando el trago es bueno para usar:

2) Si se necesita ajustar el código C++ para varios lenguajes. O si potencialmente podría haber un momento en el que uno necesita distribuir el código para varios idiomas. El uso de SWIG es confiable en este caso.

1) Si uno necesita rápidamente wrap solo varias funciones de alguna biblioteca de C++ para uso final.


Experiencia en vivo

Actualización :
Ha pasado un año y medio ya que hicimos una conversión de nuestra biblioteca mediante el uso de SWIG.

Primero hicimos una versión de python.Hubo varios momentos en los que experimentamos problemas con SWIG, es cierto. Pero en este momento hemos ampliado nuestra biblioteca a Java y .NET. Así que tenemos 3 idiomas con 1 TRAGO. Y podría decir que SWIG rocks en términos de ahorrando mucho tiempo.

Actualizar 2:
Hace dos años que usamos SWIG para esta biblioteca. SWIG está integrado en nuestro sistema de construcción. Recientemente tuvimos un cambio importante en la API de la biblioteca de C++. SWIG funcionó perfectamente. Lo único que necesitábamos hacer es añadir varios % rename a .i files so our CppCamelStyleFunctions() now looks_more_pythonish in python. Primero estaba preocupado por algunos problemas que podrían surgir, pero nada salió mal. Fue increíble. Varias ediciones y todo distribuido en 3 idiomas. Ahora lo soy seguro de que era una buena solución para usar SWIG en nuestro caso.

Actualizar 3:
Hace más de 3 años que usamos SWIG para nuestra biblioteca. Cambio mayor: la parte de python fue totalmente reescrita en python puro. La razón es que python se utiliza para la mayoría de las aplicaciones de nuestra biblioteca ahora. Incluso si la versión de pure python funciona más lento que C++ wrapping, es más conveniente para los usuarios trabajar con pure python, no tener problemas con las bibliotecas nativas.

SWIG todavía se utiliza para versiones. NET y Java.

La pregunta principal aquí "¿Usaríamos SWIG para python, si comenzamos el proyecto desde el principio?". ¡Lo haríamos! SWIG nos permitió distribuir rápidamente nuestro producto a muchos idiomas. Funcionó durante un período de tiempo que nos dio la oportunidad de comprender mejor las necesidades de nuestros usuarios.

 83
Author: MajesticRa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-22 11:35:24

CTypes es muy genial y mucho más fácil que SWIG, pero tiene el inconveniente de que el código python escrito mal o malévolamente puede bloquear el proceso python. También deberías considerar boost python. En mi humilde opinión es realmente más fácil que swig mientras que le da más control sobre la interfaz final de Python. Si está utilizando C++ de todos modos, tampoco agrega ningún otro lenguaje a su mezcla.

 13
Author: David Nehme,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 20:35:17

En mi experiencia, ctypes tiene una gran desventaja: cuando algo sale mal (e invariablemente lo hará para cualquier interfaz compleja), es un infierno para depurar.

El problema es que una gran parte de su pila está oscurecida por la magia ctypes/ffi y no hay una manera fácil de determinar cómo llegó a un punto en particular y por qué los valores de los parámetros son lo que son..

 10
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-21 01:36:28

También puede usar Pyrex, que puede actuar como pegamento entre el código Python de alto nivel y el código C de bajo nivel. lxml está escrito en Pyrex, por ejemplo.

 8
Author: Torsten Marek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 20:54:22

Voy a ser contrario y sugiero que, si puedes, deberías escribir tu biblioteca de extensiones usando la API estándar de Python . Está muy bien integrado desde la perspectiva de C y Python... si tiene alguna experiencia con la API de Perl, encontrará una muy agradable sorpresa.

Ctypes también es bueno, pero como otros han dicho, no hace C++.

¿Qué tan grande es la biblioteca que estás tratando de envolver? ¿Con qué rapidez cambia el código base? Cualquier otro ¿problemas de mantenimiento? Todo esto probablemente afectará la elección de la mejor manera de escribir los enlaces de Python.

 7
Author: Dan Lenski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-05 19:39:27

Ctypes es genial, pero no maneja clases de C++. También he encontrado que ctypes es aproximadamente un 10% más lento que un enlace directo C, pero eso dependerá en gran medida de lo que esté llamando.

Si vas a ir con ctypes, definitivamente echa un vistazo a los proyectos Pyglet y Pyopengl, que tienen ejemplos masivos de enlaces ctype.

 6
Author: Peter Shinners,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 21:22:15

Solo quería agregar algunas consideraciones más que no vi mencionadas todavía. [EDITAR: Ooops, no vi la respuesta de Mike Steder]

Si quieres intentar usar una implementación que no sea Cpython (como PyPy, IronPython o Jython), entonces ctypes es el único camino a seguir. PyPy no permite escribir extensiones C, por lo que descarta pyrex/cython y Boost.python. Por la misma razón, ctypes es el único mecanismo que funcionará para IronPython y (eventualmente, una vez que lo hagan funcionar) jython.

Como alguien más mencionó, no se requiere compilación. Esto significa que si una nueva versión de la .dll o .so sale, solo puede soltarlo y cargar esa nueva versión. Mientras ninguna de las interfaces haya cambiado, es una caída en el reemplazo.

 5
Author: Sean Toner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-04 06:13:02

Algo a tener en cuenta es que SWIG solo apunta a la implementación de CPython. Dado que ctypes también es compatible con las implementaciones PyPy e IronPython, puede valer la pena escribir sus módulos con ctypes para la compatibilidad con el ecosistema Python más amplio.

 3
Author: stderr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-25 05:35:20

He encontrado que SWIG es un poco inflado en su enfoque (en general, no solo Python) y difícil de implementar sin tener que cruzar el punto delicado de escribir código Python con una mentalidad explícita de ser amigable con SWIG, en lugar de escribir código Python limpio y bien escrito. Es, en mi humilde opinión, un proceso mucho más sencillo escribir enlaces C a C++ (si se usa C++) y luego usar ctypes para interactuar con cualquier capa de C.

Si la biblioteca a la que se está interconectando tiene una interfaz C como parte de la biblioteca, otra ventaja de ctypes es que no tiene que compilar una biblioteca separada de enlace de python para acceder a bibliotecas de terceros. Esto es particularmente bueno en la formulación de una solución de python puro que evita problemas de compilación multiplataforma (para aquellas libs de terceros que se ofrecen en plataformas dispares). Tener que incrustar código compilado en un paquete que desea implementar en algo como PyPI de una manera amigable multiplataforma es un dolor; uno de mis puntos más irritantes sobre Los paquetes de Python que utilizan SWIG o código C explícito subyacente son su multiplataforma de inavailability general. Así que considere esto si está trabajando con bibliotecas de terceros disponibles multiplataforma y desarrollando una solución python alrededor de ellas.

Como un ejemplo del mundo real, considere PyGTK. Esto (creo) usa SWIG para generar código C para interactuar con las llamadas C de GTK. Usé esto por el tiempo más breve solo para encontrar un verdadero dolor de configurar y usar, con errores extraños peculiares si no lo hiciste las cosas en el orden correcto en la configuración y solo en general. Fue una experiencia tan frustrante, y cuando miré las definiciones de interace proporcionadas por GTK en la web me di cuenta de lo sencillo que sería escribir un traductor de esas interfaces a la interfaz ctypes de python. Nació un proyecto llamado PyGGI, y en un día fui capaz de reescribir PyGTK para ser un producto mucho más funcional y útil que coincida limpiamente con las interfaces orientadas a objetos C de GTK. Y no se requiere compilación de código C por lo que es amigable multiplataforma. (En realidad estaba después de interconectar a webkitgtk, que no es tan multiplataforma). También puedo implementar PyGGI fácilmente en cualquier plataforma que soporte GTK.

 -1
Author: nak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-28 15:17:46