[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