[pyar] Problema con deadlock/starvation en __import__ dinamico dentro de un thread usando xmlrpc en el principal

Leonardo M. Rocha leo.m.rocha en gmail.com
Mar Abr 12 07:26:21 ART 2011


Hola a todos,

Les escribo porque estoy con un pequenio(gran) problema.

Si, ya se, hacer __import__ dentro de un metodo en un thread es un
poco asqueroso .... pero como que no me quedan muchas opciones.
Tambien existe importlib, pero como que no me resolvio mis necesidades
cuando la probe.

Antes de entrar a explicar el problema y pasarles todo el codigo y el
strace empiezo por explicar un poco el contexto.

En el equipo donde trabajo necesitamos de cosas que no disponemos
todavia, entonces estoy desarrollando esto:
http://www-sop.inria.fr/teams/pulsar/Girgit/ Ahi explica como bajar el
codigo completo si lo quieren ver, aunque es la version de la semana
pasada la que esta subida)
(Ojo que esa wiki esta bien fiera todavia y que la aplicacion esta
verde aun, esta semana si logro hacer andar esto, tengo un ejemplo con
grafiquitos y todo)

Que se encarga de cambiar dinamicamente cadenas de procesamiento.
La arquitectura es mas o menos la siguiente:
Tengo lo siguiente (como interesante):
Un modulo de carga dinamica de modulos clases e instancias.
Un modulo de evaluacion dinamica, que se encarga de adivinar que
componente llamar, como llamarlo, y como ordenar lo que devuelve. Y
tambien de reconfigurar las cosas cuando el event_manager le avisa que
tengo que cambiar algo y le da los datos.
Un modulo de manejo de eventos, que se encarga de ver reglas (una
regla es basicamente par: (evento, accion) con algunos detallitos mas
)
Una interfaz (si, esta bastante acoplada ... lo se y por el momento no
tengo intencion de cambiarla) cuya intencion es proveer una interfaz
para poder programar aplicaciones que la usen.

NOTA: Si ven el codigo Veran que se me ha mezclado un poco la notacion
vieja con la nueva, de a poco estoy tratando de mudar todo a la nueva
notacion de Python 3 (work in process) (lo empece antes de darme
cuenta que existia 2to3 ).

Aplicaciones:
Una para llamar desde consola, la uso desde iPython y me resulta muy
agradable para reconfigurar componentes, cadenas, prender y apagar
cosas, etc.
Otra (con la que tengo problemas) es un webservice levantado con xmlrpc

La cuestion es la siguiente:

Para poder lograr que mi modulo funcione, tengo que instanciar todo,
meterlo en un thread (y lo coloco como daemon para que se muera solo
despues) y lanzar el loop del mismo, asi no bloquea el programa que
quiera usarlo.

El encapsulamiento en thread se ve aca:
http://pastebin.com/06jK4tjE

(igual, esta en core.main de la aplicacion si quieren ver todo)

Desde consola, no tengo ningun problema, todo funciona fantastico,
puedo agregar paths en cualquier momento, instanciar nuevos objetos,
agregar y quitar componentes (que a este momento son elementos de
procesamiento de video y cosas hechas con OpenCV).

Con el servicio xmlrpc SI tengo problemas, cuando lanzo una
reconfiguracion e intenta importar un nuevo modulo se queda esperando
y esperando ad infinitum en:
(linea 155 de core/module_manager.py )

self._modules[visibility][name] = mod = __import__( module_name
,globals(),locals(),[],-1)

Codigo en pastebin para los que quieran
http://pastebin.com/Wd7jbYp2

Si mato el web service, hasta que el thread daemon se termina de
morir, se desbloquea y continua su trabajo, importa correctamente el
modulo (cualsea) y bueno tarde o temprano, como corresponde... se
termina de morir.



Mi Conclusion (y logre encontrar eso en algun lugar escondido de la
red): __import__ dentro de un thread puede llevar a un deadlock (que
probablemente tiene que ver con el GIL). Lo mas cercano que encontre
es esto: http://bugs.python.org/issue683658
Aunque en mi caso lo que se bloquea es un solo hilo.

El deadlock tiene que ver con la ejecucion del server xmlrpc:

Server xmlrpc:
http://pastebin.com/rksLVKV1

El strace donde se observa que el __import__ no termina esta aca:
http://pastebin.com/V4QPQTLD
Aunque pueden bajarlo completito de aca:
http://www-sop.inria.fr/teams/pulsar/Girgit/doku.php?id=help_with_debugging

Ahora la cuestion es COMO evitar ese problemilla, y a la vez poder
tener un loop infinito (que debe estar en un thread salvo que me den
una idea brillante para evitarlo) __import__  en cualquier lado de mi
aplicacion. La aplicacion nunca sabe que puede venir despues y la idea
es que podamos agregar cosas nuevas en tiempo de ejecucion sin parar
el proceso.

Se me ocurre (y estoy armando eso tambien) hacerlo con el modulo
multiprocessing y comunicar los procesos con algun estilo de cosa
interesante, pero me parece un poco overkill a lo que necesito

Gracias desde ya por cualquier idea, critica, solucion o contribucion.


Les cuento un poco mas, mi idea es lograr diversas aplicaciones, una
de ellas seria grafica y permitiria programar graficamente cadenas de
procesamiento (ejemplo, pipelines) (si alguno utilizo SimuLink de
Matlab), pero con unas ventajas obvias, esta hecho en Python, podria
cargar cualquier componente hecho en lo que sea con un wrapper a
Python y es libre :) (ya existe esto:
http://code.google.com/p/pylab-works/ pero para lo que me hace falta
no es suficiente y esta medio muerto ...)

Uf, se me fue largo, disculpas por eso.

Exitos,

Leo



More information about the pyar mailing list