Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What Is Async, How Does It Work, & When Should I Use It? by A. Jesse Jiryu Davis

What Is Async, How Does It Work, & When Should I Use It? by A. Jesse Jiryu Davis

PyCon 2014

April 11, 2014
Tweet

More Decks by PyCon 2014

Other Decks in Programming

Transcript

  1. What Is Async, How Does It Work, A. Jesse Jiryu

    Davis 
 @jessejiryudavis 
 MongoDB When Should I Use It? &
  2. Normal web app Client Server • Throughput bound by memory


    • Async Backend Database, OAuth service, etc. Clients
  3. Why is async hard to code? Backend Client Server request

    response store state request response time
  4. Why is async hard to code? Backend Client Server websocket

    event store state register for events event time
  5. Ways to store state: • Threads • Callbacks ! ...

    and: • Coroutines • Greenlets • Fibers • Erlang processes • and so on....
  6. So, what is async? • Single-threaded • I/O concurrency
 •

    Non-blocking sockets • epoll / kqueue • Event loop
  7. asyncio • AKA “Tulip” • Python 3.4 standard library •

    Implements PEP 3156 • Standard event loop • Coroutines
  8. 17

  9. clients = set()! ! class ChatProtocol(WebSocketServerProtocol):! def onConnect(self):! clients.add(self)! !

    def onMessage(self, msg):! for c in clients:! if c is not self:! c.sendMessage(msg)! ! def onClose(self):! clients.remove(self)! example.py How is this called?
  10. Let’s look at this example.py factory = WebSocketServerFactory(! "ws://localhost:8888")! !

    factory.protocol = ChatProtocol! ! loop = asyncio.get_event_loop()! asyncio.Task(! loop.create_server(factory, '127.0.0.1', 8888))! ! loop.run_forever()!
  11. class BaseEventLoop(events.AbstractEventLoop):! def create_server(! self, protocol_factory, host, port):! ! sock

    = socket.socket(...)! sock.bind(...)! sock.listen()! sock.setblocking(False)! ! fd = sock.fileno()! self._selector.register(! fd,! selectors.EVENT_READ,! (self._accept_connection, None))! Magic Let’s look at this asyncio reader, writer
  12. asyncio class BaseEventLoop(events.AbstractEventLoop):! def _accept_connection(! self, protocol_factory, sock):! conn, addr

    = sock.accept()! conn.setblocking(False)! ! protocol = protocol_factory()! _SelectorSocketTransport(! self, conn, protocol)! class _SelectorSocketTransport(_SelectorTransport):! def __init__(self, loop, sock, protocol):! super().__init__(loop, sock, protocol)! self._protocol.connection_made(self)! ChatProtocol This was our goal
  13. asyncio class BaseEventLoop(events.AbstractEventLoop):! def _accept_connection(! self, protocol_factory, sock):! conn, addr

    = sock.accept()! conn.setblocking(False)! ! protocol = protocol_factory()! _SelectorSocketTransport(! self, conn, protocol)! But how exactly is this called?
  14. Let’s look at this example.py factory = WebSocketServerFactory(! "ws://localhost:8888")! !

    factory.protocol = ChatProtocol! ! loop = asyncio.get_event_loop()! asyncio.Task(! loop.create_server(factory, '127.0.0.1', 8888))! ! loop.run_forever()!
  15. asyncio magic class BaseEventLoop(events.AbstractEventLoop):! def run_forever(self):! while True:! event_list =

    self._selector.select()! ! for fd, mask, data in event_list:! reader, writer = data! ! if reader and mask & EVENT_READ:! self._ready.append(reader)! ! if writer and mask & EVENT_WRITE:! self._ready.append(writer)! ! ntodo = len(self._ready)! for i in range(ntodo):! callback = self._ready.popleft()! callback()! accept_connection
  16. Review
 • asyncio uses non-blocking sockets. ! • Event loop

    tracks sockets, and the callbacks waiting for them. ! • selectors: wait for network events. ! • Event loop runs callbacks.
  17. Should I Use It? Yes: • Slow backend • Websockets

    • Many connections 29 No: • CPU-bound • No async driver • No async expertise