Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

26
Usando Twisted para hacer aplicaciones de escritorio no bloqueantes Martín Volpe @martinvol PyCon Argentina Bernal, Buenos Aires, Argentina, Noviembre 2012 Versión online: http://volteck.net/development/twisted-escritorio-charla.rar

description

Uno de los principales problemas al momento de crear aplicaciones de escritorio es el manejo del flujo de ejecución. Este problema se complica considerablemente al tener que ejecutar funciones bloqueantes. Twisted, a pesar de estar diseñado para networking, tiene una serie de herramientas para el maenjo ascincrónico del flujo facilmente adaptables a los Toolkits gráficos mas populares.

Transcript of Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Page 1: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Martín Volpe@martinvol

PyCon Argentina

Bernal, Buenos Aires, Argentina, Noviembre 2012

Versión online: http://volteck.net/development/twisted-escritorio-charla.rar

Page 2: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Aclaraciones:

• Para el objetivo de esta charla: Twisted = Asincrónico

• Twisted no es la única forma

• Los ejemplos van a ser triviales

• Los usuarios se desesperan fácil

• ¿Alguien programó en Assembler? (no se asusten!)

Page 3: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Problema:• La aplicación se congela (no necesariamente satura el CPU)

tú software

Page 4: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Objetivos de la charla:

• Entender porque las aplicaciones se bloquean

• Mostrar como Twisted se acopla a este problema

• Entender las diferentes herramientas que tiene Twisted para solucionarlos

• Entender que Twisted sólo parece magia, pero no lo es, ¡Es Python!

Page 5: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

¿Por qué pasa esto?:

# esto!while True: stuff = wait_for_stuff(timeout)

if stuff: stuff.execute() run_timed_events()

#si esto tarda en llamarse, la interfaz se bloquea refresh_GUI() #esta función de por si, tambien bloquea

¡Es culpa del reactor! ok..., para, ¿Qué es un reactor? Un loop.

• El reactor de Gtk, Qt, Wx y TKinter se pueden resumir a algo parecido a esto.

• Los que hayan programado con PyGame seguramente reconozcan este snippet

Page 6: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

¿Por qué pasa esto?:

$ python examples/1.py

Esperar eventos

Bucle del reactor

Ejecutar eventos

Page 7: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

¿Por qué pasa esto?¡¡Es culpa del reactor!! ok..., pero, ¿Que es un reactor?

$ python examples/2.py

Bucle del reactor

Callback

Tu código

Toolkit

Page 8: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Twisted:• Nada mas ni nada menos que un FrameWork escrito en Python

• Incluye un reactor extendible

• Originalmente creado para NetWorking, feature que podemos seguir utilizando para aplicaciones gráficas

• Empezó a escribirse en 2002: es maduro y estable;

• Por esto mismo: no respeta PEP8

• Es MUY extenso

• Licenciado bajo MIT License

http://twistedmatrix.com

Page 9: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Dos conceptos

• The Hollywood principle: No nos llames, nosotros te llamamos (no tan crítico en aplicaciones de escritorio)

• Multitasking cooperativo: todos compartimos el reactor, nos comprometemos a liberarlo lo mas rápido posible

Page 10: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Ejemplos típicos:• Buscar un recurso de red: urllib, sockets, etc

• Bucles y algoritmos matemáticos

• Llamadas a base de datos

• Interactuar con hardware

• print() (!!!)

• tus funciones

Estos ejemplos pueden no bloquear en todas las oportunidades, hasta que bloquean.

Casi todo se puede implementar como función no bloqueante, lo que no implica que sea la manera mas difundida (u obvia)

$ python examples/3.py$ python examples/slow_server.py &

Page 11: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Una solución: ThreadsPuede servir:

• Poco overhead

• Comparte el namespace

Pero:

• Muy poco control sobre lo que se está ejecutando (no se pueden detener!)

• Interactuar con el GIL: http://blip.tv/carlfk/mindblowing-python-gil-2243379

Un ejemplo:http://python.org.ar/pyar/Recetario/Gui/Gtk/MultiThread

Page 12: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Otra solución: MultiprocessingPuede servir:

• Se puede detener la ejecución

• Utiliza múltiples cores (si el procesador es multi-core puede correr rápido)

Pero:

• Overhead, abre otro intérprete de Python completamente independiente

• Por eso mismo: no comparte namespace (hay que usar Queues o Pipes)

http://python.org.ar/pyar/Recetario/MultiprocessingYThreading

Page 13: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Twisted: multitarea colaborativaEn el 99% de los casos esas soluciones clásicas son aplicables, pero eso no quiere decir que sean las mas adecuadas

Tiempo

Tarea 1 Tarea 2 Tarea 3

Tarea 1

Tarea 2

Tarea 3

Page 14: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Deferred:Es un objeto que nos ayuda a controlar flujos de ejecución asincrónicos

Fuente de datos

Deferred

Callbacks

Errbacks

resultado error

Page 15: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Deferred:Es un objeto que nos ayuda a controlar flujos de ejecución asincrónicos

Loop Callbacks

otros deferreds pueden ejecutarse

Page 16: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Deferred:

Sincrónico:

try:resultado = get_data_bloqueante()resultado = procesa_datos(resultado)

except Exception, e:resultado = maneja_excepcion(e)

d = get_data()d.addCallback(procesa_datos)d.addErrback(maneja_excepcion)

Asincrónico:

Page 17: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Deferred:

Sincrónico:class X:

def get_data(self):# lanzo algo que eventualmente # llame a data_readyself.d = Deferred()return self.d

def data_ready(self, data):self.d.callback(data)

service = X()service.get_data().addCallbacks(callbacks)

Page 18: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Deferred:try:

guardar_bloqueante(unDato)except Exception, e:

print "Algo no anduvo."

d = guardar_no_bloqueante(unDato) # retorna enseguida

def handle(error):print "Algo no anduvo."

d.addErrback(handle)

Page 19: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

TIP: Es importante encapsular el código

import guitoolkit

class Gui:def on_button_click(self, widget): ...def hide_entry1(self): ...

class App():def __init__(self, gui): ...def guardar(self): ...def conseguir_datos(self): ...

if __name__ == '__main__':gui_inst = Gui()App(gui_inst)guitoolkit.run()

Respetar el paradigma orientado a objetos nos ahorra dolores de cabeza:

Page 20: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Twisted entra en acción:

• Twisted es un framework diseñado para el desarrollo de aplicaciones web; es basado en eventos

• Incluye su propio reactor

• Este reactor puede ser acoplado con Gtk, Tkinter, PyUI, wxPython

• El reactor se puede acoplar a otros frameworks, como PyGame.

• Y Qt? Por problemas de licencias no está incluido con el código de twisted, pero se puede descargar por separado http://twistedmatrix.com/trac/wiki/QTReactor

Documentación sobre los diferentes reactors:http://twistedmatrix.com/documents/current/core/howto/choosing-reactor.html

Page 21: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Integrando con el toolkit gráfico:

from twisted.internet import gtk2reactor # varía dependiendo el toolkit a integrargtk2reactor.install()

# todo tu código# ...

from twisted.internet import reactor# arrancamos el reactor de twistedreactor.run()

• ¿Notaron que el código de gtk no cambio y no se rompió nada?

• Tambien hay que notar que sigue fallando en el mismo lugar, acordate: ¡Twisted no hace magia!

$ python examples/twisted/1.py

Page 22: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Herramientas que incluye Twisted: Estandariza muchas acciones comunes:

• reactor.callLater(segundos, funcion, *args, **kw), Llama a funcion despues de pasados tantos segundos

• reactor.callWhenRunning(funcion, *args, **kw), Llama a funcion cuando el reactor empieza a ejecutarse

• deferToThread(funcion, *args, **kwargs), Ejecuta funcion en otro thread y retorna un objeto Deferred

• @inlineCallbacks, transforma funciones comunes en funciones asincrónicas (para retornar hay que usar returnValue)

• Deferred.cancel(), cancelar una tarea en curso dentro de un deferred

• deferLater(reactor, segundos, funcion), ejecuta funcion pasados tantos segundos, y retorna un objeto Deferred

Y las API's de los diferentes toolkits siguen funcionando, Twisted actua como un plugin.

Page 23: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Twisted entra en acción:

Reimplementemos los ejemplos usando lo que ya sabemos:

$ python examples/twisted/2.1.py

$ python examples/twisted/2.2.py # detenible

$ python examples/twisted/3.1.py

$ python examples/twisted/3.2.py # detenible

Page 24: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Caso práctico: Donnees

• Tareas asincrónicas

• Servidor Web

• Base de datos

• Gráficos en tiempo real

• Threads implementados con Twisted

• Envío de e-mail y generación de reportes (podría haber usado twisted.mail.smtp.sendmail)

• Tomar datos del puerto serie

Repo: https://github.com/maritnvol/Donnees-Acquisition-Data-software

$ git clone [email protected]:maritnvol/Donnees-Acquisition- Data-software.git$ cd Donnees-Acquisition-Data-software/Donnees$ python tilapia.py

Page 25: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

Fuentes:

• http://www.artima.com/weblogs/viewpost.jsp?thread=230001

• http://twistedmatrix.com/documents/current/core/howto/process.html

• http://www.juanjoconti.com.ar/2010/12/01/videos-de-las-charlas-en-junin

• http://python.org.ar/pyar/CharlasAbiertas2010/Twisted

• http://krondo.com/blog/?page_id=1327

• http://mumak.net/stuff/twisted-intro.html

Page 26: Usando Twisted para hacer aplicaciones de escritorio no bloqueantes

¡¡Muchas Gracias!!

¿¿Preguntas??

Martín Volpe@martinvol

http://about.me/[email protected]

Happy Coding!