Tornado mais do que um framework bonitinho

28
Mais do que um framework web bonitinho marcelnicolay.com

description

Palestra feita no Mutirão PyCursos 2013, ela tem como objetivo introduzir os aspectos do non-blocking I/O aplicados ao desenvolvimento web e mostrar como o Tornado pode lhe ajudar a construir soluções mais completas. O Tornado é um framework web non-blocking escrito para lidar com milhares de conexões simultâneas. Iremos conhecer as camadas mais baixas do framework (ioloop, iostream, stack_context, gen, timers, ...) entender como elas funcionam e como podemos utilizá-las.

Transcript of Tornado mais do que um framework bonitinho

Page 1: Tornado   mais do que um framework bonitinho

Mais do que um framework web bonitinho

marcelnicolay.com

Page 2: Tornado   mais do que um framework bonitinho

sobre mimmarcelnicolay.comquatix.com.bracademiatech.com.br

marcelnicolay.com

Page 3: Tornado   mais do que um framework bonitinho

Tornado é um framework web non­blocking, escrito para lidar com milhares de conexõessimultâneamente.E que mais?

URL SpecTemplateLocaleRequest HandlerHTTP Server

marcelnicolay.com

Page 4: Tornado   mais do que um framework bonitinho

import tornado.ioloopimport tornado.web

class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world")

if __name__ == "__main__": application = tornado.web.Application([ (r"/", MainHandler), ]) application.listen(8888) tornado.ioloop.IOLoop.instance().start()

marcelnicolay.com

Page 5: Tornado   mais do que um framework bonitinho

mas é só isso?não...

marcelnicolay.com

Page 6: Tornado   mais do que um framework bonitinho

backgroundO que você sabe sobre:

Non­blocking I/O?Callback pass style?

marcelnicolay.com

Page 7: Tornado   mais do que um framework bonitinho

non­blocking I/OÉ um forma de processamento de entrada/saída (input/output) que não bloqueia oprocesso, permitindo executar outras coisas em paralelo.

Operações de entrada e saída, como leitura e escrita, podem ser extremamente lentas emcomparação com o processamento.

Por exemplo, durante uma operação de disco que leve 10 milisegundos para ser realizada,um processador de 1 gigahertz pode processar até 10milhões de instruções.

marcelnicolay.com

Page 8: Tornado   mais do que um framework bonitinho

non­blocking I/OTypical flow of the synchronous blocking I/O model

marcelnicolay.com

Page 9: Tornado   mais do que um framework bonitinho

asynchronous I/OTypical flow of the asynchronous non­blocking I/O model

marcelnicolay.com

Page 10: Tornado   mais do que um framework bonitinho

non­blocking I/OEverything in unix is a file descriptor

incluindo:

socketsconnections

marcelnicolay.com

Page 11: Tornado   mais do que um framework bonitinho

client server

sockets operations

marcelnicolay.com

Page 12: Tornado   mais do que um framework bonitinho

synchronous accept

marcelnicolay.com

Page 13: Tornado   mais do que um framework bonitinho

asynchronous accept

marcelnicolay.com

Page 14: Tornado   mais do que um framework bonitinho

callback passing styledef start(foo): # do stuff with foo and when donw call the next function stuff(callback=next_step, data=foo);

def next_step(bar): # call more_stuff to parse bar more_stuff(callback=last_step, data=bar)

def last_step(baz): # senf the response send_response(baz)

#let our handler know we are done finish()

marcelnicolay.com

Page 15: Tornado   mais do que um framework bonitinho

IOLoopAn I/O event loop for non­blocking sockets.

core da camada de rede do tornadorápido e fácil de usaruma instância por processocross­plataformacódigo abertoclient libraries & server applications

marcelnicolay.com

Page 16: Tornado   mais do que um framework bonitinho

IOLoopimport errnoimport functoolsimport socketfrom tornado import ioloop

def handle_connection(connection, address): print "new connection..."

def connection_ready(sock, fd, events): while True: try: connection, address = sock.accept() except socket.error, e: if e.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN): raise return connection.setblocking(0) handle_connection(connection, address)

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)sock.setblocking(0)sock.bind(("", 8888))sock.listen(128)

io_loop = ioloop.IOLoop.instance()callback = functools.partial(connection_ready, sock)io_loop.add_handler(sock.fileno(), callback, io_loop.READ)io_loop.start()

marcelnicolay.com

Page 17: Tornado   mais do que um framework bonitinho

IOStreamUtility classes to write to and read from non­blocking files and sockets.

faz todo o "trabalho sujo" para vocêtambém usado em client & server

marcelnicolay.com

Page 18: Tornado   mais do que um framework bonitinho

IOStream: a very simple HTTP clientfrom tornado import ioloopfrom tornado import iostreamimport socket

def send_request(): stream.write("GET / HTTP/1.0\r\nHost: friendfeed.com\r\n\r\n") stream.read_until("\r\n\r\n", on_headers)

def on_headers(data): headers = {} for line in data.split("\r\n"): parts = line.split(":") if len(parts) == 2: headers[parts[0].strip()] = parts[1].strip() stream.read_bytes(int(headers["Content-Length"]), on_body)

def on_body(data): print data stream.close() ioloop.IOLoop.instance().stop()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)stream = iostream.IOStream(s)stream.connect(("friendfeed.com", 80), send_request)ioloop.IOLoop.instance().start()

Page 19: Tornado   mais do que um framework bonitinho

tornado.stack_contextpermite preservar o estado atual para ser usado em um outro contexto de execução

@contextlib.contextmanagerdef die_on_error(): try: yield except Exception: logging.error("exception in asynchronous operation",exc_info=True) sys.exit(1)

with StackContext(die_on_error): # Any exception thrown here *or in callback and its desendents* # will cause the process to exit instead of spinning endlessly # in the ioloop. http_client.fetch(url, callback)ioloop.start()

marcelnicolay.com

Page 20: Tornado   mais do que um framework bonitinho

tornado.genNão curtiu o 'callback passing style'?

class AsyncHandler(RequestHandler): @asynchronous def get(self): http_client = AsyncHTTPClient() http_client.fetch("http://example.com", callback=self.on_fetch)

def on_fetch(self, response): do_something_with_response(response) self.render("template.html")

marcelnicolay.com

Page 21: Tornado   mais do que um framework bonitinho

tornado.genExiste uma forma mais 'pythonica' de fazer isso...

class GenAsyncHandler(RequestHandler): @asynchronous @gen.engine def get(self): http_client = AsyncHTTPClient() response = yield gen.Task(http_client.fetch, "http://example.com") do_something_with_response(response) self.render("template.html")

marcelnicolay.com

Page 22: Tornado   mais do que um framework bonitinho

timersexecutar um callback na próxima iteração, ou após algum intervalo

ioloop.add_timeout(deadline, callback)ioloop.remove_timeout(timeout)ioloop.add_callback(callback)

marcelnicolay.com

Page 23: Tornado   mais do que um framework bonitinho

tornado.httpclient.AsyncHTTPClientAn non­blocking HTTP client.

from tornado import ioloop, httpclient

def handle_request(response): if response.error: print "Error:", response.error else: print response.body ioloop.IOLoop.instance().stop()

http_client = httpclient.AsyncHTTPClient()http_client.fetch("http://www.google.com/", handle_request)ioloop.IOLoop.instance().start()

Page 24: Tornado   mais do que um framework bonitinho

tornado.platform.twistedThis module contains a Twisted reactor build on the Tornado IOLoop

import tornado.platform.twistedtornado.platform.twisted.install()from twisted.internet import reactor

marcelnicolay.com

Page 25: Tornado   mais do que um framework bonitinho

tornado.websocketWebSockets allow for bidirectional communication between the browser and server.

class EchoWebSocket(websocket.WebSocketHandler): def open(self): print "WebSocket opened"

def on_message(self, message): self.write_message(u"You said: " + message)

def on_close(self): print "WebSocket closed"

marcelnicolay.com

Page 26: Tornado   mais do que um framework bonitinho

tornado.netutil.TCPServerA non­blocking, single­threaded TCP server.

from tornado import ioloopfrom tornado import netutil

class EchoServer(netutil.TCPServer):

def handle_stream(self, stream, address): self._stream = stream self._read_line()

def _read_line(self): self._stream.read_until('\n', self._handle_read)

def _handle_read(self, data_in): self._stream.write('You sent: %s' % data_in) self._read_line()

if __name__ == '__main__': server = EchoServer() server.listen(2007) ioloop.IOLoop.instance().start())

marcelnicolay.com

Page 27: Tornado   mais do que um framework bonitinho

Mais do que um framework bonitinho

marcelnicolay.com

Page 28: Tornado   mais do que um framework bonitinho

referênciashttp://en.wikipedia.org/wiki/Asynchronous_I/Ohttp://www.kegel.com/dkftpbench/nonblocking.htmlhttp://www.kernel.org/doc/man­pages/online/pages/man4/epoll.4.htmlhttp://scotdoyle.com/python­epoll­howto.htmlhttp://docs.python.org/2/library/select.htmlhttp://www.tornadoweb.org/documentation/index.htmlhttp://dabeaz.com/coroutines/Coroutines.pdf

marcelnicolay.com