44
Asychronous I/O in Python 3 Feihong Hsu Chicago Python User Group July 11, 2013

Asynchronous I/O in Python 3

Embed Size (px)

DESCRIPTION

Feihong talks about PEP 3156 and basic usage of Tulip, the reference implementation. Video: http://pyvideo.org/video/2194/asynchronous-io-in-python-3 Source code: https://github.com/feihong/tulip-talk/

Citation preview

Page 1: Asynchronous I/O in Python 3

Asychronous I/O in Python 3

Feihong HsuChicago Python User Group

July 11, 2013

Page 2: Asynchronous I/O in Python 3

What is PEP 3156?

• "Asynchronous IO Support Rebooted"

• Describes a new event loop API

• Aims to be compatible with current popular event loops (Twisted, Tornado, etc.)

• Should land in the standard library in 3.4 (early 2014)

Page 3: Asynchronous I/O in Python 3

The big take-away

We're going to be able to write asynchronous code without threads or callbacks!

Page 4: Asynchronous I/O in Python 3

Threads vs event loop

• I'm not going to talk about this

• Twisted being around for more than a decade kinda validates the event loop model

• For a detailed discussion see An Intro to Asynchronous Programming and Twisted

Page 5: Asynchronous I/O in Python 3

Twisted vs Tulip

Ugh, how to explain this?

I could just give you a boring list of differences...

Or I could use an analogy...

Page 6: Asynchronous I/O in Python 3

Programming with Twisted is like...

Being a mystical ninja warrior!

Page 7: Asynchronous I/O in Python 3

Mystical Ninja Warrior

• Can defeat demons and demigods by deploying an army of shadow clones

• Mental gymnastics required to coordinate shadow clones requires years of brutal training

• Ninja magic comes with a terrible price: the more clones you make, the more insane you become

Page 8: Asynchronous I/O in Python 3

Programming with Tulip is like...

Playing Plants Vs Zombies

Page 9: Asynchronous I/O in Python 3

Playing Plants Vs Zombies

• Can defeat a zombie horde by deploying and managing a large number of horticultural specimens

• Not particularly mentally taxing

• Somehow end up playing for hours without eating or sleeping

Page 10: Asynchronous I/O in Python 3

Alrighty

With the analogies out of the way, let's look at some examples.

Page 12: Asynchronous I/O in Python 3

Control flow diagram

I was going to draw one but then I got sleepy.

Page 13: Asynchronous I/O in Python 3

Problems with callback-based asynch code

• Can be hard to understand control flow

• Error messages are not friendly

• Debugging is harder

Page 17: Asynchronous I/O in Python 3

The Tulip API

• Basics are documented in PEP 3156

• Not available in Python Package Index

• Includes sockets, file I/O, etc.

• Includes concurrency data structures like locks, queues, semaphores

• Includes SSL and HTTP (with support for websockets!)

Page 18: Asynchronous I/O in Python 3

Coroutines vs tasks

When I first started, the most confusing thing about Tulip.

Coroutines are executed by "yield from".

Tasks are not executed by "yield from".

Page 19: Asynchronous I/O in Python 3

Coroutine

• Basically a function that contains at least one "yield from" statement.

• Not the same thing as a generator function, which is a function that contains a yield expression.

• Tulip will barf if you try to make it execute a generator.

Page 20: Asynchronous I/O in Python 3

Coroutine

@tulip.coroutine

def download(url):

response = yield from tulip.http.request('GET', url)

return yield from response.read()

Calling "download()" returns a generator object, but otherwise does nothing! You need to do "yield from download()" to run the body of a coroutine.

Page 21: Asynchronous I/O in Python 3

Task

• An object that manages a coroutine

• Roughly equivalent to the Deferred object in Twisted

Page 22: Asynchronous I/O in Python 3

[email protected]

def download(url):

response = yield from tulip.http.request('GET', url)

return yield from response.read()

Calling "download()" actually does run the body of the function. The "yield from" part is done implicitly for you.

Page 23: Asynchronous I/O in Python 3

Task

In Tulip, there are two ways of creating tasks:

tulip.task is a decorator that produces a task-wrapping function

tulip.Task is a constructor that accepts a coroutine

Page 24: Asynchronous I/O in Python 3

Why bother to use tasks?

• To interoperate with callback-based frameworks like Twisted

• To cancel an already-running coroutine

• To start a new coroutine from within another coroutine

Page 25: Asynchronous I/O in Python 3

Wait, so what's a Future?

PEP 3156 makes frequent mention of Futures.

But talking about Futures is a little confusing, since there are two Future classes: tulip.Future and concurrent.futures.Future.

Page 26: Asynchronous I/O in Python 3

Future is the superclass of Task

• Future don't necessarily manage a coroutine

• In practice you never create Future objects, only Task objects

• Futures are acceptable to yield from expressions

Page 27: Asynchronous I/O in Python 3

Methods on Future

• cancel(), cancelled()

• running(), done()

• result(), set_result()

• add_done_callback(), remove_done_callback()

• ...

Page 28: Asynchronous I/O in Python 3

Web development with Tulip

• All the classes you need are in the tulip.http module

• Make subclass of tulip.http.ServerHttpProtocol

• Override the handle_request() method

Page 30: Asynchronous I/O in Python 3

Some observationsThe HTTP API is fairly simple, but a bit low level for everyday web programming.

Expect a thousand microframeworks to bloom in the near future.

Speaking of microframeworks...

Page 31: Asynchronous I/O in Python 3

Introducing viol

• Tiny web framework based on Tulip

• After initial page load, messages between client and server are exchanged via websockets

• Makes code demos a bit more visual

Page 32: Asynchronous I/O in Python 3

Tulip API demos

Now for a bunch of demos...

Page 33: Asynchronous I/O in Python 3

Tulip API demos

Page 44: Asynchronous I/O in Python 3

Questions?