tornado mais do que um framework bonitinho

28
Mais do que um framework web bonitinho marcelnicolay.com

Upload: marcel-nicolay

Post on 04-Dec-2014

2.515 views

Category:

Technology


2 download

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

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