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

D21717ea76044d31115c573d368e6ff4?s=128

PyCon 2014

April 11, 2014
Tweet

Transcript

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

    Davis 
 @jessejiryudavis 
 MongoDB When Should I Use It? &
  2. Food in NYC • Subs • Pizza • Omakase

  3. Subs Counter ⚇! client ⚇! sandwich! maker pool ☺

  4. CPU-bound web app Client Server Clients • Throughput bound by

    computation
 • No async
  5. Pizza 5 Counter ⚇! client ⚇! pizza
 cook ☺ oven

    ⚇⚇⚇
  6. Normal web app Client Server • Throughput bound by memory


    • Async Backend Database, OAuth service, etc. Clients
  7. Omakase 7 Counter ⚇! waiter kitchen ⚇⚇⚇! clients

  8. Websocket application Client Server sockets Events sockets Clients • Number

    of clients bound by memory
 • Async
  9. What’s async for? Minimizes resources per connection.

  10. C10K kegel.com/c10k.html

  11. Why is async hard to code? Backend Client Server request

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

    event store state register for events event time
  13. Ways to store state: Coding difficulty Threads Callbacks Memory per

    connection
  14. Ways to store state: • Threads • Callbacks ! ...

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

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

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

  18. Layers 18 Application Protocol Transport Event Loop Selectors asyncio {

    autobahn websockets example.py
  19. from autobahn import (WebSocketServerProtocol,! WebSocketServerFactory)! example.py

  20. 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?
  21. 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()!
  22. 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
  23. 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
  24. 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?
  25. 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()!
  26. 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
  27. Application asyncio’s event loop start_server() register(fd,! accept_connection) accept_connection() run_forever() onConnect()

  28. 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.
  29. Should I Use It? Yes: • Slow backend • Websockets

    • Many connections 29 No: • CPU-bound • No async driver • No async expertise
  30. A. Jesse Jiryu Davis 
 @jessejiryudavis 
 MongoDB