[Python-es] Threads con operaciones I/O en Python
Francesc Alted
faltet en pytables.org
Lun Jun 7 17:07:05 CEST 2010
A Monday 07 June 2010 15:57:40 Félix Palazuelos Pérez escrigué:
> Hola, estoy inmerso en el desarrolo de una aplicación de audio via 485 con
> ossaudiodev y speex en python. Un ordenador tendra una gui en wxPython y un
> botón de hablar, al ir todo por puerto serie había pensado en crear un hilo
> para escuchar las tramas del puerto serie y el principal con la gui. ¿Mejor
> hilos que procesos teneindo en cuenta que el trabajo de speex (extensión en
> C) lo va a hacer el hilo? Necesito la máxima rápidez, ya que si no el
> sonido se entrecortaría. A ver si me podeís aconseja ren rendimiento de
> hilos y eso. Muchas gracias a todos :)
El debate de hilos vs procesos es muy intenso y da para mucho. En general, si
hablamos de C, los hilos te permiten obtener máxima eficiencia ya que puedes
acceder a la memoria de los otros hilos sin limitación alguna. El problema es
que, para evitar que dos hilos escriban al mismo tiempo una cierta posición de
memoria, has de usar funciones de bloqueo o sincronía, y esto suele ser
difícil de codificar (y más aún de testear).
Por otra parte, existen librerías que permiten el intercambio de datos entre
diferentes procesos y aunque, en general, éstas no son tan eficientes como el
uso de hilos, a cambio, el mecanismo de bloqueo queda integrado en la propia
libreria, por lo que su programación es más sencilla (así como el testeo).
En Python se pueden usar ambas aproximaciones, pero con una pequeña diferencia
con respecto a C: cuando uses hilos, el intérprete te va a hacer bloqueos
automáticos cada vez que haces cálculos en el espacio de Python (esto es lo
que se llama Global Interpreter Lock o, abreviadamente, GIL). La ventaja es
que tú no te tienes que preocupar de implementar los bloqueos (Python lo hace
por tí), pero el gran inconveniente es que los bloqueos son de grano tan
grueso que dos hilos no se pueden ejecutar nunca de manera concurrente. Sin
embargo, es importante decir que, si vas a usar extensiones, siempre puedes
deshabilitar el GIL cuando entres en la extensión, y usar hilos en C para
poder beneficiarte de la concurrencia en máquinas multi-core.
En general, los hilos en C son la opción más eficiente, pero es bastante
difícil programar un algoritmo hilado en C y no morir en el intento (léase,
que tus programas funcionen correctamente). Así que mi consejo es que uses
los hilos nativos de Python, y en caso que quieras concurrencia con multi-
cores, hacer uso del módulo `multiprocessing`, que viene de serie desde le
Python 2.6 y que, usando la misma API de `threading`, te permite simular los
threads con auténticos procesos, lo que te permite concurrencia verdadera.
Evidentemente, `multiprocessing` necesita de transmisión de datos entre los
diferentes procesos, así como de bloqueos para poder emular los threads
correctamente, lo que siempre te va a restar prestaciones. Que tu aplicación
se ejecute mejor con `threading` o con `multiprocessing` va a depender de tu
código, pero la ventaja es que la conversión de un programa para que use un
módulo u otro necesita de muy poco esfuerzo por parte del programador (e
incluso con un poco de esfuerzo adicional se puede hacer que se use un módulo
u otra de manera dinámica).
De todas maneras, esto es un debate muy frecuente en la lista de Python en
inglés (aunque también en la de castellano), por lo que te recomiendo echarle
un vistazo a sus archivos pues te pueden aportar muchas cosas aparte de lo que
te comento aquí.
--
Francesc Alted
Más información sobre la lista de distribución Python-es