$30 off During Our Annual Pro Sale. View Details »

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?
    &

    View Slide

  2. Food in NYC
    • Subs
    • Pizza
    • Omakase

    View Slide

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

    View Slide

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

    • No async

    View Slide

  5. Pizza
    5
    Counter
    ⚇!
    client
    ⚇!
    pizza

    cook

    oven

    ⚇⚇⚇

    View Slide

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

    • Async
    Backend
    Database,
    OAuth service,
    etc.
    Clients

    View Slide

  7. Omakase
    7
    Counter
    ⚇!
    waiter
    kitchen
    ⚇⚇⚇!
    clients

    View Slide

  8. Websocket application
    Client Server
    sockets
    Events
    sockets
    Clients
    • Number of clients bound by memory

    • Async

    View Slide

  9. What’s async for?
    Minimizes resources per connection.

    View Slide

  10. C10K
    kegel.com/c10k.html

    View Slide

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

    View Slide

  12. Why is async hard to code?
    Backend
    Client Server
    websocket
    event
    store state
    register for events
    event
    time

    View Slide

  13. Ways to store state:
    Coding difficulty
    Threads
    Callbacks
    Memory per connection

    View Slide

  14. Ways to store state:
    • Threads
    • Callbacks
    !
    ... and:
    • Coroutines
    • Greenlets
    • Fibers
    • Erlang processes
    • and so on....

    View Slide

  15. So, what is async?
    • Single-threaded
    • I/O concurrency

    • Non-blocking sockets
    • epoll / kqueue
    • Event loop

    View Slide

  16. asyncio
    • AKA “Tulip”
    • Python 3.4 standard library
    • Implements PEP 3156
    • Standard event loop
    • Coroutines

    View Slide

  17. 17

    View Slide

  18. Layers
    18
    Application
    Protocol
    Transport
    Event Loop
    Selectors
    asyncio
    {
    autobahn websockets
    example.py

    View Slide

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

    View Slide

  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?

    View Slide

  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()!

    View Slide

  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

    View Slide

  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

    View Slide

  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?

    View Slide

  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()!

    View Slide

  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

    View Slide

  27. Application asyncio’s event loop
    start_server()
    register(fd,!
    accept_connection)
    accept_connection()
    run_forever()
    onConnect()

    View Slide

  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.

    View Slide

  29. Should I Use It?
    Yes:
    • Slow backend
    • Websockets
    • Many connections
    29
    No:
    • CPU-bound
    • No async driver
    • No async expertise

    View Slide

  30. A. Jesse Jiryu Davis

    @jessejiryudavis

    MongoDB

    View Slide