25
More than just a pretty web framework: the Tornado IOLoop Gavin M. Roy

The Tornado IOLoop

Embed Size (px)

DESCRIPTION

Given at PyCon 2012 in Santa Clara, CA

Citation preview

Page 1: The Tornado IOLoop

More than just a pretty web framework:the Tornado IOLoop

Gavin M. Roy

Page 2: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

According to comScore, myYearbook is one of the 25 most-trafficked sites in the United States as measured by page views, by minutes, and by minutes per visitor per month.

About myYearbook

PyCon 2012 Follow me on Twitter: @Crad

http://www.myyearbook.com/careers

Page 3: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

Tornado @ myYearbook

• At myYearbook, we used Tornado in high-request-velocity applications.

• Web apps

• Finite State Machine Game Server

• Take what you need? We do.

Page 4: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

Async Network Programming

• Core revolves around an I/O loop

• Let the Operating System indicate when to read, when to write and when there are errors on sockets.

• select, poll, epoll (Linux), kqueue (BSD)

• Callback-Passing Style

Page 5: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

Async Network Programming

Page 6: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

def start(foo): # Do stuff with foo and when done 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): # Send the response send_response(baz) # Let our handler know we are done finish()

Callback Passing Style

Page 7: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

tornado.IOLoop

• Core of Tornado’s network stack

• Fast and easy to use

• Single instance per process

• Cross-platform

• Easy to read source: http://goo.gl/VFeAF

• Used for client libraries & server applications

Works on windows but not supported.

C-Based epoll, not required

Page 8: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

tornado.IOStream

• Convenient utility class for dealing with the IOLoop

• Does most of the work for you

• This too is for use by clients and server applications

Page 9: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

IOStream: How to read

• read_until_regex(regex, callback)

• read_until(delimiter, callback)

• read_bytes(num_bytes, callback, streaming_callback=None)

• read_until_close(callback, streaming_callback=None)

Page 10: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

IOStream: What’s Going On?

reading(), writing(), closed()

Page 11: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

Serious Business Uses

SSL

And that’s why SSLIOStream Exists.

Page 12: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

tornado.netutil.TCPServer

Page 13: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

Hello Async Worldfrom 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() Source: http://goo.gl/eB7z4

Page 14: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

What just happened?

tornado.stack_context.StackContext

“Slight Magic”

Page 15: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

Diving Deeper

Page 16: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

tornado.IOLoop

•IOLoop.instance()

•ioloop.add_handler(fd, handler, events)

•ioloop.update_handler(fd, handler, events)

•ioloop.remove_handler(fd)

Page 17: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

Events?

READ, WRITE, ERROR

Page 18: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

“Example”import socketfrom tornado import ioloop

def on_events(fd, events, error=None):

if events & ioloop.IOLoop.READ: print 'Socket read: %r' % fd.recv(1024)

if events & ioloop.IOLoop.ERROR: print 'Error received: %r' % error

if events & ioloop.IOLoop.WRITE: pass

_ioloop = ioloop.IOLoop.instance()fd = socket.socket() # Other stuff needs to be done hereevents_desired = ioloop.IOLoop.READ | ioloop.IOLoop.ERROR _ioloop.add_handler(fd, on_events, events_desired)_ioloop.start()

Page 19: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

Timers

• add_timeout(deadline, callback)

• remove_timeout(timeout)

add_timeout returns a reference

deadline can be unix timestamp or a datetime.timedelta

Page 20: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

add_callback(callback)

Page 21: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

“Pythonic” Simplification

Page 22: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

tornado.gen

@gen.enginedef foo(): http_client = AsyncHTTPClient() response1, response2 = yield [gen.Task(http_client.fetch, url1), gen.Task(http_client.fetch, url2)]

for coding not in Callback Passing Style:

Page 23: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

tornado.platform.twisted

Page 24: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

Last Thoughts

• Single threaded, use processes

• Watch out for resource contention

• Benchmark your application

• Fork work to remote workers

• multiprocessing.reduction

Page 25: The Tornado IOLoop

PyCon 2012 Follow me on Twitter: @Crad

# Main processfrom multiprocessing.reduction import reduce_handle

h = reduce_handle(client_socket.fileno())

pipe_to_worker.send(h) #instance of multiprocessing.Pipe

# Worker processfrom multiprocessing.reduction import rebuild_handle

h = pipe.recv()fd = rebuild_handle(h)client_socket = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)client_socket.send("hello from the worker process\r\n")

multiprocessing.reduction:

Questions?