
Cómo utilizar los IO-Channels de GLib desde Python para implementar el patrón reactor.
Los IO Channels de GLib son una forma muy elegante y eficiente de manejar múltiples fuentes de datos asíncronas simultáneas. En un sistema Unix cualquier entrada de datos se puede ver como un fichero. Eso permite que ficheros, pipes, terminales, puertos serie, sockets y casi cualquier cosa se puedan tratar de forma homogénea. Además, también se pueden utilizar eventos activados por tiempo.
En términos de diseño, se considera que el bucle de eventos de GLib es una implementación del patrón de diseño Reactor.
Es obvio que no tiene mucho sentido un módulo glib en Python, pues la mayoría de las features de esta librería ya las soporta de serie el lenguaje. Tampoco tiene sentido un módulo GObject pues Python soporta orientación a objetos de forma nativa.
Sin embargo, el bucle de eventos de GTK está realmente en GObject y esa es la razón principal de que haya un módulo GObject para Python. Todo esto viene muy bien porque no hay una implementación “estándar” de un bucle de eventos genérico para Python.
Resumiendo, el módulo gobject disponible en Python es la respuesta si lo que buscamos es un “reactor” genérico y portable.
Lo que aparece a continuación es un programa completo (aunque inútil) que demuestra cómo se puede usar gobject para implementar un reactor con tres fuentes:
Los handlers deben devolver True, de otro modo son automáticamente eliminados después de su ejecución:
import sys, os, socket import gobject def file_handler(fd, condition): print os.read(fd.fileno(), 32) return True def timer_handler(): print 'timeout' return True udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udp_sock.bind(('',9000)) gobject.timeout_add(3000, timer_handler) gobject.io_add_watch(sys.stdin, gobject.IO_IN, file_handler) gobject.io_add_watch(udp_sock.makefile(), gobject.IO_IN, file_handler) gobject.MainLoop().run()
Para probar la fuente UDP se puede usar netcat:
$ nc -u host 9000
Si por cualquier circunstancia necesitas crear tú el bucle de eventos y no puedes usar MainLoop, todavía puedes usar la gestión de eventos de gobject por medio de iteration().
Ten en cuenta que, en este caso, el tratamiento no es bloqueante. El bucle consumirá toda la CPU disponible, pero se supone que la necesitas para hacer algún tipo de cómputo intensivo. Si no es ese tu caso, deberías volver a plantearte si lo que te conviene es usar directamente el “mainloop”, como en el ejemplo del punto anterior.
Para el bucle anterior sería algo como:
[...] gobject.io_add_watch(udp_sock.makefile(), gobject.IO_IN, file_handler) while 1: gobject.main_context_default().iteration(False) ...tus tareas...
Pero atención, si necesitas asegurarte de que se sirve algún evento antes de seguir cada iteración, tendrás que ejecutar el método iteration() hasta que devuelva True:
[...] gobject.io_add_watch(udp_sock.makefile(), gobject.IO_IN, file_handler) while 1: while not gobject.main_context_default().iteration(): pass ...tareas...
Comentarios recientes
hace 3 horas 16 mins
hace 1 día 16 horas
hace 2 días 1 hora
hace 4 días 14 horas
hace 1 semana 1 día
hace 1 semana 2 días
hace 1 semana 2 días
hace 1 semana 3 días
hace 1 semana 3 días
hace 1 semana 3 días