Python, do you even async?

52
Python, do you even async? Saúl Ibarra Corretgé @saghul DomCode, August 2014

description

Talk given at DomCode meetup in Utrecht (August 2014) on different frameworks to do asynchronous I/O y Python, with a strong focus on asyncio (PEP-3156).

Transcript of Python, do you even async?

Page 1: Python, do you even async?

Python, do you even async?

Saúl Ibarra Corretgé@saghul

DomCode, August 2014

Page 2: Python, do you even async?

repr(self)>>> from Amsterdam import saghul>>>>>> saghul.work()VoIP, SIP, XMPP, chat, Real Time Communications>>>>>> saghul.other()networking, event loops, sockets, MOAR PYTHON>>>>>> saghul.languages()Python, C>>>

Page 3: Python, do you even async?

github.com/saghul

Page 4: Python, do you even async?

Please give feedback!https://joind.in/event/view/2471

Page 5: Python, do you even async?

The road toasynchronous i/o

Page 6: Python, do you even async?

import socketimport socket!server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)server.bind(('127.0.0.1', 1234))server.listen(511)print("Server listening on: {}".format(server.getsockname()))!client, addr = server.accept()print("Client connected: {}".format(addr))!while True: data = client.recv(4096) if not data: print("Client has disconnected") break client.send(data)!server.close()

Page 7: Python, do you even async?

except Exception:

• We can only handle one client at a time!• Solutions for handling multiple clients• Threads

• I/O multiplexing

• Check the C10K problem if you haven’t already!• http://www.kegel.com/c10k.html

Page 8: Python, do you even async?

try: sockets + threadsimport socketimport thread!def handle_client(client, addr): print("Client connected: {}".format(addr)) while True: data = client.recv(4096) if not data: print("Client has disconnected") break client.send(data.upper())!server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)server.bind(('127.0.0.1', 1234))server.listen(511)print("Server listening on: {}".format(server.getsockname()))!while True: client, addr = server.accept() thread.start_new_thread(handle_client, (client, addr))

Page 9: Python, do you even async?

except Exception:

• Threads have overhead• Stack size

• Context switching

• Synchronisation • GIL? • Not for I/O!

Page 10: Python, do you even async?

I/O multiplexing

• Examine and block for I/O in multiple file descriptors at the same time• Single thread

• A file descriptor is ready if the corresponding I/O operation can be performed without blocking

• File descriptor has to be set to benon-blocking

Page 11: Python, do you even async?

I/O is hard

• Different paradigms in Unix vs Windows• “are you ready?” vs “call me later”

• Frameworks• Abstract platform differences

• Provide tools for easier development of applications

Page 12: Python, do you even async?
Page 13: Python, do you even async?

The included batteries

• select• asyncore / asyncchat

• selectors• asyncio

Page 14: Python, do you even async?

“batteries don’t fit”http://bit.ly/182HcHT

Page 15: Python, do you even async?

Frameworks

• Platform abstraction• Protocol implementations• Integration with other event loops: Qt,

GLib, ...• Different API styles• Async file i/o?

Page 16: Python, do you even async?

import twisted

• Uses select, poll, kqueue, epoll from the select module

• IOCP on Windows• Integration with other event loops• Factory / Protocol / Transport

abstractions• Deferreds

Page 17: Python, do you even async?

import tornado

• Uses select, poll, kqueue, epoll from the select module

• select() on Windows :-(• Mainly oriented to web development• Synchronous looking API with

coroutines / Futures

Page 18: Python, do you even async?

import gevent

• Uses libev for platform abstraction

• select() on Windows :-(

• Syncronous API using greenlet

• ME LIKEY! :-)

Page 19: Python, do you even async?

Solution!

Page 20: Python, do you even async?

I’m not trying to reinvent the wheel. I’m trying to build a good one. !

Guido van Rossum

Page 21: Python, do you even async?

import tulipasyncio

Page 22: Python, do you even async?

import asyncio

• Reference implementation for PEP-3156

• Basic components for doing async i/o• Works on Python >= 3.3• Trollius: backport for Python >= 2.6

Page 23: Python, do you even async?

Goals

• Modern implementation of asynchronous i/o for Python

• Use yield from (PEP-380)• But don’t force it

• Don’t use anything that requiresPython > 3.3

• Interoperability with other frameworks

Page 24: Python, do you even async?

Goals

• Unix and Windows support

• IPv4 and IPv6

• TCP, UDP and pipes

• Basic SSL (secure by default)

• Subprocesses

Page 25: Python, do you even async?

Non goals

• Perfection• Replacing current frameworks• Protocol implementations• Replace httplib, smtplib, ...• Make it work on Python < 3.3

Page 26: Python, do you even async?

Interoperability

selectors iocp

asyncio

twisted tornado gevent ...

Page 27: Python, do you even async?

Example: Tornado

asyncio / twisted

tornado

epoll/kqueue

tornado

Page 28: Python, do you even async?

Architecture

Page 29: Python, do you even async?

Components

Event loop, policy

Coroutines, Futures, Tasks

Transports, Protocols, Streams

Page 30: Python, do you even async?

Event loop

Calculatepoll time Poll

Runcallbacks

Page 31: Python, do you even async?

Event loop & policy

• Chooses the best i/o mechanism for a given platform

• APIs for creating server and client connections (TCP, UDP, …)

• Establish the context for a loop

Page 32: Python, do you even async?

Working with threads

• loop.call_soon_threadsafe(func, *args)• loop.run_in_executor(exc, func, *args)• loop.set_default_executor(exc)

!

• PEP-3148 executor

Page 33: Python, do you even async?

Coroutines, Futures & Tasks

Page 34: Python, do you even async?

Coroutines, Futures & Tasks

• Coroutines• a generator function, can receive values

• decorated with @coroutine

• Future• promise of a result or an error

• Task• Future which runs a coroutine

Page 35: Python, do you even async?

Coroutines & yield fromimport asyncioimport socket!loop = asyncio.get_event_loop()[email protected] handle_client(client, addr): print("Client connected: {}".format(addr)) while True: data = yield from loop.sock_recv(client, 4096) if not data: print("Client has disconnected") break client.send(data)[email protected] accept_connections(server_socket): while True: client, addr = yield from loop.sock_accept(server_socket) asyncio.async(handle_client(client, addr))!server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)server.bind(('127.0.0.1', 1234))server.listen(511)server.setblocking(False)print("Server listening on: {}".format(server.getsockname()))!loop.run_until_complete(accept_connections(server))

Page 36: Python, do you even async?

Coroutines & yield from

• Imagine the yield from is not there• Imagine the code is executed

sequentially• Not exactly the formal definition of yield

from (from PEP-380)

Page 37: Python, do you even async?

Futures

• Similar to Futures from PEP-3148• API (almost) identical• Adapted for asyncio’s single threaded

model

Page 38: Python, do you even async?

Futures + Coroutines

• yield from works with Futures!• f = Future()• Someone will set the result or exception

• r = yield from f• Waits until done and returns f.result()

• Usually returned by functions

Page 39: Python, do you even async?

Undoing callbacks (I)

@asyncio.coroutinedef sync_looking_function(*args): fut = asyncio.Future() def cb(result, error): if error is not None: fut.set_result(result) else: fut.set_exception(Exception(error)) async_function(cb, *args) return (yield from fut)

Page 40: Python, do you even async?

Undoing callbacks (II)

!def sync_looking_function(*args): fut = asyncio.Future() def cb(result, error): if error is not None: fut.set_result(result) else: fut.set_exception(Exception(error)) async_function(cb, *args) return fut

Page 41: Python, do you even async?

Tasks

• Unicorns covered in fairy dust• It’s a coroutine wrapped in a Future• Inherits from Future• Works with yield from• r = yield from Task(coro(...))

Page 42: Python, do you even async?

Tasks vs coroutines

• A coroutine doesn’t “advance” without a scheduling mechanism

• Tasks can advance in their own• The event loop is the scheduler!

Page 43: Python, do you even async?

Exampleimport asyncio!loop = asyncio.get_event_loop()clients = {} # task -> (reader, writer)!def accept_client(client_reader, client_writer): task = asyncio.Task(handle_client(client_reader, client_writer)) clients[task] = (client_reader, client_writer)! def client_done(task): del clients[task]! task.add_done_callback(client_done)[email protected] handle_client(client_reader, client_writer): while True: data = (yield from client_reader.readline()) client_writer.write(data)!!f = asyncio.start_server(accept_client, '127.0.0.1', 12345)server = loop.run_until_complete(f)loop.run_forever()

Page 44: Python, do you even async?

Transports & Protocols

Page 45: Python, do you even async?

Transports & Protocols

• Transport: represents a connection (socket, pipe, ...)

• Protocol: represents an application (HTTP server, IRC client, ...)

• They always go together

• API is based on function calls and callbacks

Page 46: Python, do you even async?

Streams

• Abstraction on top of transports / protocols

• File-like API using coroutines

Page 47: Python, do you even async?

Transport -> Protocol

• connection_made(transport)• data_received(data)• eof_received()• connection_lost(exc)

!

• UDP, pipes and subprocesses are slightly different

Page 48: Python, do you even async?

Protocol -> Transport

• write(data)• writelines(seq)• write_eof()• close()

Page 49: Python, do you even async?

Enter Trollius!

• Backport of asyncio for Python >= 2.6

• By Victor Stinner (@haypo)

• Slightly different syntax

• yield instead of yield from

• raise Return(x) instead of return x on generators

• pip install trollius

Page 50: Python, do you even async?

That was all?!

• Go read PEP-3156

• Implement a simple protocol (an IRC client for example)

• Checkout the links on the last slide

• Use asyncio in your next project

Page 51: Python, do you even async?

Questions?

bettercallsaghul.com@saghul

Page 52: Python, do you even async?

Links

• https://code.google.com/p/tulip/

• http://legacy.python.org/dev/peps/pep-3156/

• https://code.google.com/p/tulip/wiki/ThirdParty

• http://asyncio.org/

• http://www.slideshare.net/saghul