Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Food in NYC • Subs • Pizza • Omakase

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

CPU-bound web app Client Server Clients • Throughput bound by computation
 • No async

Slide 5

Slide 5 text

Pizza 5 Counter ⚇! client ⚇! pizza
 cook ☺ oven ⚇⚇⚇

Slide 6

Slide 6 text

Normal web app Client Server • Throughput bound by memory
 • Async Backend Database, OAuth service, etc. Clients

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

What’s async for? Minimizes resources per connection.

Slide 10

Slide 10 text

C10K kegel.com/c10k.html

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

So, what is async? • Single-threaded • I/O concurrency
 • Non-blocking sockets • epoll / kqueue • Event loop

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

17

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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?

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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?

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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.

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

A. Jesse Jiryu Davis 
 @jessejiryudavis 
 MongoDB