python, do you even async?
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
![Page 1: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/1.jpg)
Python, do you even async?
Saúl Ibarra Corretgé@saghul
DomCode, August 2014
![Page 2: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/2.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/3.jpg)
github.com/saghul
![Page 5: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/5.jpg)
The road toasynchronous i/o
![Page 6: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/6.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/7.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/8.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/9.jpg)
except Exception:
• Threads have overhead• Stack size
• Context switching
• Synchronisation • GIL? • Not for I/O!
![Page 10: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/10.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/11.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/12.jpg)
![Page 13: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/13.jpg)
The included batteries
• select• asyncore / asyncchat
• selectors• asyncio
![Page 15: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/15.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/16.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/17.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/18.jpg)
import gevent
• Uses libev for platform abstraction
• select() on Windows :-(
• Syncronous API using greenlet
• ME LIKEY! :-)
![Page 19: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/19.jpg)
Solution!
![Page 20: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/20.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/21.jpg)
import tulipasyncio
![Page 22: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/22.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/23.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/24.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/25.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/26.jpg)
Interoperability
selectors iocp
asyncio
twisted tornado gevent ...
![Page 27: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/27.jpg)
Example: Tornado
asyncio / twisted
tornado
epoll/kqueue
tornado
![Page 28: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/28.jpg)
Architecture
![Page 29: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/29.jpg)
Components
Event loop, policy
Coroutines, Futures, Tasks
Transports, Protocols, Streams
![Page 30: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/30.jpg)
Event loop
Calculatepoll time Poll
Runcallbacks
![Page 31: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/31.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/32.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/33.jpg)
Coroutines, Futures & Tasks
![Page 34: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/34.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/35.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/36.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/37.jpg)
Futures
• Similar to Futures from PEP-3148• API (almost) identical• Adapted for asyncio’s single threaded
model
![Page 38: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/38.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/39.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/40.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/41.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/42.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/43.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/44.jpg)
Transports & Protocols
![Page 45: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/45.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/46.jpg)
Streams
• Abstraction on top of transports / protocols
• File-like API using coroutines
![Page 47: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/47.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/48.jpg)
Protocol -> Transport
• write(data)• writelines(seq)• write_eof()• close()
![Page 49: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/49.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/50.jpg)
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?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/51.jpg)
Questions?
bettercallsaghul.com@saghul
![Page 52: Python, do you even async?](https://reader037.vdocuments.site/reader037/viewer/2022102716/555a22cbd8b42a900d8b460f/html5/thumbnails/52.jpg)
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