Pregunta

En Python, ¿en qué circunstancias es SWIG una mejor opción que ctypes para llamar a puntos de entrada en bibliotecas compartidas? Supongamos que aún no tiene el (los) archivo (s) de interfaz SWIG.

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

¿Fue útil?

Solución

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

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

Es probable que, en ejecución pura, SWIG sea más rápido que ctypes, porque la administración en torno al 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 interconecte muchas funciones diferentes de C, 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 archivos .c y compilarlos, no tiene que desproteger y silenciar advertencias. Simplemente puede saltar y comenzar a usar una sola función C con un mínimo esfuerzo, luego expandirla a más. Y puedes probar y probar cosas directamente en el intérprete de Python. Envolver un montón de 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 (salvo los detalles específicos del idioma que se deben completar, como el código C personalizado que mencioné anteriormente). Cuando se incluyen muchos y muchos códigos 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.

Otros consejos

Tengo una rica experiencia en el uso de 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. En general, conduce a inconvenientes:
- necesita configuración (plantillas SWIG .i), a veces es complicado,
- falta de tratamiento de algunos casos especiales (ver propiedades de python más adelante),
- Falta de rendimiento en algunos idiomas.

Contras de Python:

1) Inconsistencia de estilo de código . C ++ y Python tienen estilos de código muy diferentes (lo que es obvio, sin duda), las posibilidades de un trago de hacer que el código objetivo sea más Pythonish son muy limitadas. Como ejemplo, es importante crear propiedades a partir de captadores y definidores. Consulte esta q & amp; a

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

Pros:

  • 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 otros 20 idiomas (!!!)

  • Una gran preocupación acerca de SWIG es el rendimiento. Desde la versión 2.04, SWIG incluye el indicador '-builtin' que hace que SWIG sea incluso más rápido que otras formas automatizadas de ajuste. Al menos algunos puntos de referencia lo muestra.


¿Cuándo usar SWIG?

Entonces, llegué a la conclusión de dos casos cuando el trago es bueno de usar:

2) Si es necesario envolver el código C ++ para varios idiomas . 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 necesita rápidamente envolver solo varias funciones de alguna biblioteca de C ++ para uso final.


Experiencia en vivo

Actualizar :
Ha pasado un año y medio, ya que hicimos una conversión de nuestra biblioteca utilizando SWIG.

Primero, hicimos una versión de python. Hubo varios momentos en los que tuvimos problemas con SWIG, es cierto. Pero ahora mismo expandimos nuestra biblioteca a Java y .NET. Así que tenemos 3 idiomas con 1 SWIG. Y podría decir que SWIG oscila en términos de ahorrar MUCHO tiempo.

Actualización 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 teníamos que hacer es agregar varios% cambio de nombre a los archivos .i para que nuestro CppCamelStyleFunctions () ahora looks_more_pythonish en python. Primero me preocuparon algunos problemas que podrían surgir, pero nada salió mal. Fue increíble. Solo varias ediciones y todo distribuido en 3 idiomas. Ahora confío en que fue una buena solución utilizar SWIG en nuestro caso.

Actualización 3 :
Hace más de 3 años que usamos SWIG para nuestra biblioteca. Cambio importante : la parte de python se reescribió totalmente en python puro. La razón es que Python se usa para la mayoría de las aplicaciones de nuestra biblioteca ahora. Incluso si la versión de python puro funciona más lentamente que el envoltorio de C ++, es más conveniente para los usuarios trabajar con python puro, sin tener que luchar con las bibliotecas nativas.

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

La pregunta principal aquí "¿Usaríamos SWIG para python si comenzáramos 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 los requisitos de nuestros usuarios.

CTypes es muy bueno y mucho más fácil que SWIG, pero tiene el inconveniente de que un código de Python mal escrito o malintencionado puede bloquear el proceso de Python. También debe considerar boost . En mi humilde opinión es más fácil que tomar un trago mientras te da más control sobre la interfaz final de Python. De todos modos, si está utilizando C ++, tampoco agrega otros idiomas a su mezcla.

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 tu pila está oculta por ctypes / ffi magic y no hay una manera fácil de determinar cómo llegaste a un punto en particular y por qué los valores de los parámetros son lo que son ...

También puede utilizar Pyrex , que puede actúa 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.

Voy a ser contraria y sugeriré que, si puede, debe escribir su biblioteca de extensión utilizando API estándar de Python . Está realmente bien integrado tanto desde la perspectiva de C como de Python ... si tiene alguna experiencia con la API de Perl, encontrará que es una sorpresa agradable muy .

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

¿Qué tan grande es la biblioteca que estás tratando de envolver? ¿Qué tan rápido cambia el código base? ¿Algún otro problema de mantenimiento? Probablemente todos estos afectarán la elección de la mejor forma de escribir los enlaces de Python.

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

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

Solo quería agregar algunas consideraciones más que aún no había visto. [EDIT: Ooops, no vi la respuesta de Mike Steder]

Si desea intentar usar una implementación que no sea de Cpython (como PyPy, IronPython o Jython), entonces ctypes es la única manera de hacerlo. 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 funcionen) jython.

Como alguien más mencionó, no se requiere compilación. Esto significa que si sale una nueva versión de .dll o .so, simplemente puede soltarla y cargar esa nueva versión. Mientras no se modifique ninguna de las interfaces, es un reemplazo.

Algo que se debe tener en cuenta es que SWIG se dirige solo a la implementación de CPython. Como ctypes también es compatible con las implementaciones de PyPy y IronPython, puede valer la pena escribir sus módulos con ctypes para que sean compatibles con el ecosistema Python más amplio.

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

Si la biblioteca a la que se está conectando tiene una interfaz en C como parte de la biblioteca, otra ventaja de los ctypes es que no tiene que compilar una biblioteca de enlace de python separada para acceder a bibliotecas de terceros. Esto es particularmente bueno al formular una solución de python puro que evita problemas de compilación multiplataforma (para aquellas librerías de terceros que se ofrecen en plataformas dispares). Tener que integrar código compilado en un paquete que desea implementar en algo como PyPi de una manera amigable multiplataforma es una molestia; Uno de mis puntos más irritantes sobre los paquetes de Python que utilizan SWIG o el código C explícito subyacente es su multiplataforma general de disponibilidad. Entonces, considere esto si está trabajando con bibliotecas de terceros disponibles multiplataforma y está desarrollando una solución de Python a su alrededor.

Como un ejemplo del mundo real, considere PyGTK. Esto (creo) usa SWIG para generar código C para interactuar con las llamadas GTK C. Utilicé esto por un breve tiempo solo para encontrar un verdadero problema de configuración y uso, con errores extraños extravagantes si no 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 interfaces proporcionadas por GTK en la web, me di cuenta de lo sencillo que sería escribir un traductor de esa interfaz a la interfaz de Python ctypes. Nació un proyecto llamado PyGGI, y en UN día pude reescribir PyGTK para que sea un producto mucho más funcional y útil que coincida perfectamente con las interfaces orientadas a objetos C de GTK. Y no requería una compilación de código C que lo hiciera compatible con varias plataformas. (En realidad estaba después de interactuar con webkitgtk, que no es tan multiplataforma). También puedo implementar fácilmente PyGGI en cualquier plataforma que soporte GTK.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top