2010-07-21 17 views
6

Tengo un programa existente que tiene su propio bucle principal, y realiza cálculos basados ​​en la entrada que recibe, digamos del usuario, para hacerlo simple. Ahora quiero hacer los cálculos de forma remota en lugar de localmente, y decidí implementar los RPC en Twisted.Usar mi propio bucle principal en twisted

Idealmente solo quiero cambiar una de mis funciones, por ejemplo doComputation(), para hacer una llamada a retorcida para realizar la RPC, obtener los resultados y regresar. El resto del programa debe permanecer igual. ¿Cómo puedo lograr esto, sin embargo? Twisted secuestra el lazo principal cuando llamo al reactor.run(). También leí que realmente no tienes hilos en retorcido, que todas las tareas se ejecutan en secuencia, por lo que parece que no puedo simplemente crear un LoopingCall y ejecutar mi ciclo principal de esa manera.

Respuesta

8

Tiene un par de opciones diferentes, dependiendo de qué tipo de ciclo principal tenga su programa actual.

Si se trata de un mainloop de una biblioteca de GUI, Twisted may already have support for it. En ese caso, puedes seguir y usarlo.

También podría escribir su propio reactor. No hay mucha documentación excelente para esto, pero you can look at the way that qtreactor implementa un plugin de reactor externamente a Twisted.

También puede escribir un reactor mínimo usando threadedselectreactor. La documentación para esto también es escasa, pero the wxpython reactor se implementa utilizando. Personalmente, no recomendaría este enfoque, ya que es difícil de probar y puede dar lugar a condiciones de carrera confusas, pero tiene la ventaja de permitirle aprovechar casi todos los códigos de red predeterminados de Twisted con solo una capa delgada de envoltura.

Si está realmente seguro de que usted no quiere que su doComputation ser asincrónicas, y quiere que su programa para bloquear a la espera de Twisted para responder, haga lo siguiente:

  • inicio en otro hilo trenzado antes de que se inicie el ciclo principal, con algo como twistedThread = Thread(target=reactor.run); twistedThread.start()
  • crea una instancia de un objeto para hacer su comunicación RPC (digamos, RPCDoer) en el hilo de su ciclo principal, para que tenga una referencia. Asegúrese de iniciar realmente su lógica Twisted con reactor.callFromThread para que no tenga que envolver todas sus llamadas Twisted API.
  • Implemente RPCDoer.doRPC, usando solo llamadas Twisted API (es decir, no llame al código de la aplicación existente, por lo que no necesita preocuparse por la seguridad de subprocesos para sus objetos de aplicación; pase doRPC toda la información que necesita como argumentos).
  • Ahora puede aplicar doComputation así:

    def doComputation(self): 
        rpcResult = blockingCallFromThread(reactor, self.myRPCDoer.doRPC) 
        return self.computeSomethingFrom(rpcResult) 
    
  • recuerde llamar reactor.callFromThread(reactor.stop); twistedThread.join() del procedimiento de cierre de su principal de circuito, de lo contrario puede ver algunas trazas de retorno confusos o registrar los mensajes de salida.

Por último, una opción que realmente debería considerar, especialmente a largo plazo: descargue su bucle principal existente y descubra una forma de utilizar Twisted. Según mi experiencia, esta es la respuesta correcta para 9 de cada 10 personas que hacen preguntas como esta. No estoy diciendo que esto sea siempre el camino a seguir - hay muchos casos en los que realmente necesita mantener su propio bucle principal, o donde es demasiado esfuerzo para deshacerse del bucle existente.Pero, mantener tu propio bucle también funciona. Tenga en cuenta que el bucle retorcido ha sido probado exhaustivamente por millones de usuarios y utilizado en una gran variedad de entornos. Si su ciclo también es extremadamente maduro, puede no ser un gran problema, pero si está escribiendo un programa pequeño y nuevo, la diferencia en la confiabilidad puede ser significativa.

+2

gracias por la gran respuesta! Estoy inclinado hacia dos desde la 2da hasta la última aproximación, pero no pienso en reemplazar mi ciclo principal. ahora, ¿hay algún beneficio en ejecutar twisted en un hilo separado vs. ejecutarlo como hilo principal, y llamar a mi bucle principal con 'reactor.callInThread()'? – Claudiu

+0

blockingcallfromtrhead es la manera de ir – Claudiu

0

Parece que la respuesta correcta y muy simple aquí es un LoopingCall:

http://www.saltycrane.com/blog/2008/10/running-functions-periodically-using-twisteds-loopingcall/

from datetime import datetime 
from twisted.internet.task import LoopingCall 
from twisted.internet import reactor 

def doComputation(): 
    print "Custom fn run at", datetime.now() 

lc = LoopingCall(doComputation) 
lc.start(0.1) # run your own loop 10 times a second 

# put your other twisted here 

reactor.run()