Programación asincrónica en Python Twisted
asynchronous (2)
Tengo problemas para desarrollar un proxy inverso en Twisted. Funciona, pero parece demasiado complejo y enrevesado. Mucho se siente como vudú.
¿Hay algún ejemplo simple y sólido de estructura de programa asíncrona en la web o en libros? ¿Una especie de guía de mejores prácticas? Cuando complete mi programa, me gustaría seguir viendo la estructura de alguna manera, sin mirar un plato de espagueti.
Si no está buscando usar retorcido, había una gran guía que utilicé hace un tiempo. Aquí está el enlace a él .
Twisted contiene una gran cantidad de ejemplos . Uno en particular, el tutorial "evolución de los dedos" , contiene una explicación detallada de cómo un programa asíncrono crece desde un kernel muy pequeño hasta un sistema complejo con muchas partes móviles. Otro que podría interesarle es el tutorial sobre simplemente escribir servidores .
Lo más importante a tener en cuenta acerca de Twisted, o incluso de otras bibliotecas de red asíncronas (como asyncore , MINA o ACE ), es que su código solo se invoca cuando sucede algo. La parte que he oído a menudo suena como "vudú" es la administración de devoluciones de llamada: por ejemplo, Deferred
. Si está acostumbrado a escribir código que se ejecuta en línea recta y solo llama a funciones que regresan inmediatamente con resultados, la idea de esperar que algo le devuelva la llamada podría ser confusa. Pero no hay nada mágico, no hay "vudú" sobre devoluciones de llamadas. En el nivel más bajo, el reactor está sentado y esperando que ocurra una de una pequeña cantidad de cosas:
- Los datos llegan a una conexión (llamará a los datos
dataReceived
en un protocolo) - Ha pasado el tiempo (llamará a una función registrada con
callLater
). - Se ha aceptado una conexión (llamará a
buildProtocol
en una fábrica registrada con una funciónlistenXXX
oconnectXXX
). - Se ha desconectado una conexión (se llamará
connectionLost
en el protocolo apropiado)
Cada programa asíncrono comienza conectando algunos de estos eventos y luego arranca el reactor para esperar a que sucedan. Por supuesto, los eventos que suceden llevan a más eventos que se conectan o desconectan, por lo que su programa sigue su camino feliz. Más allá de eso, no hay nada especial acerca de la estructura del programa asíncrono que sea interesante o especial; los controladores de eventos y las devoluciones de llamada son solo objetos, y su código se ejecuta de la manera habitual.
Aquí hay un simple "motor impulsado por eventos" que muestra cuán simple es este proceso.
# Engine
import time
class SimplestReactor(object):
def __init__(self):
self.events = []
self.stopped = False
def do(self, something):
self.events.append(something)
def run(self):
while not self.stopped:
time.sleep(0.1)
if self.events:
thisTurn = self.events.pop(0)
thisTurn()
def stop(self):
self.stopped = True
reactor = SimplestReactor()
# Application
def thing1():
print ''Doing thing 1''
reactor.do(thing2)
reactor.do(thing3)
def thing2():
print ''Doing thing 2''
def thing3():
print ''Doing thing 3: and stopping''
reactor.stop()
reactor.do(thing1)
print ''Running''
reactor.run()
print ''Done!''
En el núcleo de las bibliotecas como Twisted, la función en el ciclo principal no es sleep
, sino una llamada al sistema operativo como select()
o poll()
, como se expone en un módulo como el módulo de selección de Python . Digo "me gusta" select
, porque esta es una API que varía mucho entre las plataformas, y casi todos los kits de herramientas GUI tienen su propia versión. Twisted actualmente proporciona una interfaz abstracta para 14 variaciones diferentes sobre este tema. Lo común que ofrece una API así es proporcionar una forma de decir "Aquí hay una lista de eventos que estoy esperando. Dormir hasta que uno de ellos suceda, luego despertar y decirme cuál de ellos fue. "