Async/await in Python 3.5 and why it is awesome
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Part Number | 80 | |
Number of Parts | 169 | |
Author | ||
License | CC Attribution - NonCommercial - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/21243 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
EuroPython 201680 / 169
1
5
6
7
10
11
12
13
18
20
24
26
29
30
31
32
33
36
39
41
44
48
51
52
53
59
60
62
68
69
71
79
82
83
84
85
90
91
98
99
101
102
106
110
113
114
115
118
122
123
124
125
132
133
135
136
137
140
143
144
145
147
148
149
151
153
154
155
156
158
162
163
166
167
169
00:00
Core dumpSoftware developerLecture/ConferenceMeeting/InterviewComputer animation
00:23
Core dumpSoftware developerPauli exclusion principleWebsiteStack (abstract data type)BitSurgeryMultiplication signSingle-precision floating-point formatSoftware testingSurvival analysisComputer programmingAuthorizationParallel computingElectronic signatureWeightAlpha (investment)Pauli exclusion principleCoroutineCore dumpSoftware developerLecture/ConferenceMeeting/InterviewComputer animation
01:40
Library (computing)Event horizonGreen's functionElectric generatorSinc functionExpressionLimit (category theory)CoroutineLecture/Conference
02:02
WeightExpressionElectric generatorStatement (computer science)Functional (mathematics)Limit (category theory)DemosceneSemantics (computer science)Source codeInstance (computer science)Single-precision floating-point formatException handlingExtension (kinesiology)Sinc functionCoroutineFrictionComputer animation
03:21
ResultantRevision controlFunctional (mathematics)Control flowElectric generatorQuery languageSoftwareEqualiser (mathematics)NeuroinformatikSystem callComputer programmingLecture/ConferenceComputer animation
03:58
Source codeCore dumpElectric generatorCoroutineLecture/Conference
04:18
Data typeSystem callFunction (mathematics)Formal languageDemosceneWeightMechanism designPoint (geometry)Frame problemFunctional (mathematics)Software frameworkMultiplication signNeuroinformatikElectric generatorDifferent (Kate Ryan album)CoroutineConstructor (object-oriented programming)Computer clusterType theoryComputer animation
05:38
Profil (magazine)ResultantMultiplication signCoroutineNormal (geometry)System callExtension (kinesiology)Local ringWeightFunctional (mathematics)Lecture/Conference
06:05
LogicCoroutineProcess (computing)Interpreter (computing)Electric generatorWeightQuicksortLecture/Conference
06:35
Data typeSource codeShared memoryEqualiser (mathematics)Electric generatorGroup actionDemosceneImplementationDirected graphSynchronizationContext awarenessData managementObject (grammar)Type theoryCoroutineCommunications protocolCodeTerm (mathematics)OpcodeComputer animation
07:07
Real numberObject (grammar)CodeReal numberWeightInformation securityStatement (computer science)Database transactionBlock (periodic table)MereologyVideo gameSystem callDatabaseFerry CorstenLecture/ConferenceComputer animation
07:38
Real numberImplementationDatabaseDevice driverFunctional (mathematics)Query languageDirected graphCursor (computers)IterationLecture/ConferenceComputer animation
08:08
Software developerMereologyStandard deviationPort scannerSoftware frameworkBitTerm (mathematics)DatabaseDevice driverImplementationLibrary (computing)MereologyStandard deviationInstance (computer science)Directed graphFrame problemLecture/ConferenceComputer animation
08:39
Decision theoryGoodness of fitStability theoryLibrary (computing)Multiplication signBuildingWhiteboardDifferent (Kate Ryan album)Finite differenceComputing platformPhysical systemPoint (geometry)Direction (geometry)MereologyLecture/Conference
09:11
Software developerMereologyStandard deviationPort scannerEvent horizonCodeCartesian coordinate systemComputer animationLecture/Conference
09:31
Event horizonInterface (computing)Server (computing)Task (computing)Queue (abstract data type)SynchronizationCodeImplementationConnected spaceStreaming mediaBridging (networking)Task (computing)Interface (computing)Server (computing)Event horizonCommunications protocolHeat transferLoop (music)Factory (trading post)WeightParameter (computer programming)Transportation theory (mathematics)Service (economics)Reading (process)Single-precision floating-point formatComputer animation
10:07
Queue (abstract data type)SynchronizationPrimitive (album)CASE <Informatik>Interactive televisionProcess (computing)Speech synthesisEvent horizonSemaphore lineLecture/Conference
10:29
Instance (computer science)Event horizonLine (geometry)Task (computing)Loop (music)CoroutineObject (grammar)Number2 (number)Functional (mathematics)ProgrammschleifeGame controllerSoftware frameworkCondition numberEqualiser (mathematics)SequenceComputer programmingSingle-precision floating-point formatWeightSystem callComputer animation
12:24
Functional (mathematics)Roundness (object)Task (computing)Event horizonLoop (music)BitCoroutineLecture/ConferenceComputer animation
13:07
DataflowSource codeProteinFunctional (mathematics)CoroutineLoop (music)Parameter (computer programming)CodeThread (computing)Process (computing)Lecture/ConferenceComputer animation
13:50
Software testingLoop (music)Parallel computingModule (mathematics)Loop (music)Functional (mathematics)Closed setVariable (mathematics)Inheritance (object-oriented programming)Integrated development environmentCodeComputer programmingAsynchronous Transfer ModeSoftware bugEvent horizonLecture/ConferenceComputer animation
14:47
Error messageComputer programmingModule (mathematics)Function (mathematics)Software-defined radioLecture/Conference
15:11
Letterpress printingInstance (computer science)Default (computer science)Ring (mathematics)Software testingConfiguration spaceRegular graphFunctional (mathematics)System callLecture/Conference
15:30
Software testingLoop (music)Event horizonTask (computing)Inheritance (object-oriented programming)Functional (mathematics)WeightSystem callLevel (video gaming)Computer programmingLattice (order)Structural loadFormal languageImplementationEvent horizonLoop (music)Exterior algebraLecture/ConferenceComputer animation
16:12
Goodness of fitLoop (music)ImplementationTask (computing)System callWeightLecture/Conference
16:36
Socket-SchnittstelleBenchmarkSoftware frameworkServer (computing)QuicksortBitMultiplication signWordProduct (business)Cartesian coordinate systemImplementationTheoryQuality of serviceTraffic reportingStructural loadLatent heatLoop (music)Lecture/ConferenceXMLUML
17:32
Pauli exclusion principleIdeal (ethics)Online helpServer (computing)ImplementationPauli exclusion principleParameter (computer programming)Formal languageLecture/ConferenceComputer animation
18:13
Right angleReduction of orderSound effectStandard deviationDatabase transactionCodeRollback (data management)Lecture/Conference
18:40
Pauli exclusion principlePrototypeIterationEmailPatch (Unix)ImplementationFreezingComplete metric spaceEmailProduct (business)Drop (liquid)RadiusPrototypePatch (Unix)Pauli exclusion principleLecture/ConferenceComputer animation
19:27
Process (computing)Software developerPauli exclusion principleData structureCore dumpType theoryLecture/Conference
20:13
Pauli exclusion principleMetric systemSign (mathematics)Instance (computer science)Operator (mathematics)Arithmetic meanImplementationComputer programmingLecture/Conference
20:37
Multiplication signBuildingContext awarenessData managementForcing (mathematics)Radical (chemistry)Event horizonLoop (music)JSONXMLComputer animationLecture/Conference
21:00
Loop (music)Data managementContext awarenessEvent horizonComplex (psychology)Closed setComputer programmingMetadataCausalityLecture/Conference
21:34
Lecture/Conference
21:54
Core dumpMathematical optimizationDrop (liquid)Lecture/Conference
22:18
Code refactoringCore dumpDecision theorySoftware developerSpeicherbereinigungCodeData managementAbstractionPhysical systemNeuroinformatikEqualiser (mathematics)Level (video gaming)Lecture/Conference
23:35
Scripting languageSoftware repositoryBenchmarkSoftware frameworkInstance (computer science)Traffic reportingLecture/Conference
24:14
Condition numberRow (database)Spring (hydrology)PreconditionerLecture/Conference
24:44
Information systemsRed HatLecture/ConferenceComputer animation
Transcript: English(auto-generated)
00:00
I'd like to introduce Yuri Zilivanov. He's a Python core developer and the main developer behind Async.io coming from Toronto, Canada to us. Giving a warm welcome, please.
00:22
So this talk is an introduction to Async Await and to Async.io. It's nothing like my previous talk. This talk is basically for beginners. So a little bit about me. I'm co-founder of Magic Stack. Check out our website, it's magic.io. I'm in love with Python users since 2008
00:41
and I believe, I just started to use Python 3 when it was alpha 2 and I never looked back, so use Python 3. I'm C Python core developer since 2013. I think I started to contribute a little bit earlier than that, but still. I co-authored with Brett Cannon and Larry Hastings,
01:00
PEP 362, that's inspect signature API. I authored and implemented PEP 492, that's Async Await syntax. I maintained Async.io with Guida and Victor Steiner and I also created UVloop and AsyncPG. Let's talk about coroutines in Python. So there are five obvious ways to do coroutines in Python.
01:22
The first one is callbacks and deferreds. Not exactly coroutines, but a way to do asynchronous programming. Twisted has been with us since 2002 and I believe that's the first time you could actually do asynchronous programming in Python reliably.
01:40
Then we had stackless Python and greenlets. I'm pretty sure everybody knows libraries like G event and eventlet. Those are great examples of how you integrate those features. Since Python 2.5, we could create coroutines using generators and yield expressions. Although there were some limitations with this approach,
02:03
first is performance and the second one is that you couldn't actually use return statement in generators. Since Python 3.3, we had yield from syntax and Async.io for instance uses that extensively. And in Python 3.5, we have Async Await.
02:22
So let's take a look how coroutines using yield expression look like. This is an actual example from twisted documentation. Old grumpy coroutine. But if you look at the source code, you will see that there is no return statement. That you have to kinda use a function to return. What this function does internally,
02:41
it rises an exception. And that's how this limitation that you cannot use return statement was overcome. Yield from coroutines, since Python 3.3, they look much better actually. It's recommended to use Async.io coroutine decorator,
03:01
but it's not required. And you have to use yield from. A lot of problems with this approach were that people actually didn't understand what yield from is and when to use it and then how it actually works. What do you have to put from? So we had some friction
03:20
with actually teaching people how to use that. And also there is a slight problem with generators in general. If you don't use this Async.io decorator, let's say you have the first version of your software with a coroutine called compute. And you compute something, you sleep for one second,
03:42
and then you return the result. And in version two, you decided to make your users happy and you removed the Async.io sleep call. And now your function doesn't have any yield from. So now it's not a coroutine, now it's not a generator. So your program just breaks. To ensure it never happens, you have to use Async.io coroutine.
04:01
But some people forget. And also when you look at a lot of source code and you see lots and lots of yield froms, you kind of stop understanding where are the coroutines and what are the generators and how they interact with each other. So it's all been a mess. And in Python 3.5, we introduced Async.await.
04:21
So we don't need any decorators now. Even if the function doesn't have any awaits inside, we know it's a coroutine because of the async keyword. So why do I think that Async.await is the answer how you do coroutines in Python? Well, first of all, first time in Python history we have dedicated syntax for coroutines. It's concise, it's readable,
04:43
it's easy to teach people how to use. We also have new built-in type for coroutines, again for the first time in Python history. It's not a subtype of generators anymore. It's its own thing. We also have AsyncFor and AsyncWith constructs.
05:00
And these, I believe, are kind of unique to Python. I know no other language that allows you to do that kind of magic. And Async.await is actually a generic mechanism. A lot of people think that Async.await is somehow tied to Async.io. It's not true. Actually, Tornado uses Async.await now.
05:21
Twisted is about to start using Async.await. And there is another framework called Curio which uses Async.await in an entirely different way from Async.io. And also Async.await is fast. If you write, let's say, a Fibonacci function and then time coroutines versus normal functions,
05:42
you will see that coroutines are only two times slower, which is totally fine, because even in large Async.io applications, you usually have 50, maybe 100 await calls per request, but you have thousands or hundreds of thousands of normal calls. So use Async.await extensively. Don't worry about it.
06:01
It won't show up in your profile results. And also, Async.await is faster. Async.await and yield from are faster, actually, than the old approach of using yield coroutines, because a lot of logic of how you actually resume and how you push values to coroutines
06:21
before had to be implemented in Python, and now it's the job of Python interpreters to do that, so it's much, much faster. So coroutines are subtypes of generators, but not in Pythonic sense. In Pythonic sense, generators and coroutines are completely different objects. They are subtypes in terms of C implementation.
06:41
They actually share the same C struct layout. They share a lot of code, like 95% code is shared. And it actually shows, if you disassemble a coroutine, you will see that it still uses yield from opcode. We also have types coroutine decorator that allows you to transform any generator into a coroutine, so it's compatible with Async.await syntax.
07:03
And we have a bunch of protocol methods for asynchronous generators and asynchronous context managers and future-like objects. You can read about all of that in PEP492. So how does Async.await code look in real life? It's quite easy, actually.
07:21
You can see that we have a serious coroutine, then we have an await call that prepares a database statement, then we enter a transaction. And here is an interesting part about Async.with, actually, it allows you to execute some asynchronous code when you enter the block and allows you to execute some asynchronous code when you exit the block. So it's quite important, actually,
07:41
to implement database drivers where you kinda need this functionality. And then you can see Async.for, which is also unique. It allows you to call asynchronous code while iterating. So in this example, actually, cursor prefetches you some data. You iterate over it efficiently,
08:01
and when you iterate over all prefetched data, it prefetches even more. So it's quite efficient to iterate over large data sets. Now let's talk about Async.io. So it's developed by Guido himself, at least initially. A lot of people think that Async.io is a framework. I think it's a little bit wrong term to use for Async.io.
08:21
I view it more as a toolbox, as a collection of tools for framework creators to use. For instance, Async.io doesn't have any HTTP implementation. It doesn't have any database drivers. You have to install libraries to do that. It's also part of standard library.
08:40
And this is both good and bad. It's good because everybody, if something ends up being in standard library, it will be supported. It will be supported until the end of time, basically. So it's a good and stable business decision to actually use Async.io. Python also has a huge collection of build boards for different platforms and different operating systems.
09:02
And it's quite important to actually test Async.io on all of them because I always is really hard. And another exciting point about Async.io is that Twisted soon and Tornado right now, they can actually integrate with Async.io. So in theory, you can actually run existing
09:21
Tornado applications on top of Async.io event loop. So the code reuse possibilities are just exciting. So what's inside Async.io? So we have standardized and pluggable event loop. You can actually swap the event loop implementation with something else, if you want. Async.io also defines a bunch of interfaces for protocols and transfers.
09:42
It has factories for creating servers and connections and streams. It also defines futures and tasks. Futures are essentially a bridge between old callback style code and new Async Await style code. And task is also something really fundamental.
10:02
So task is what we actually call coroutine runner. It's something that allows event loop to actually run coroutines, to suspend them, to push values into them and resume them. And then we have APIs to create and interact with subprocesses asynchronously. We have queues and we have synchronization primitives
10:22
like locks, events, semaphores, and other stuff. And Async.io is simple. This is actually a screenshot of Async.io documentation. It only takes you five days to read it and a couple of months to digest. And then you can actually use it.
10:41
So joking aside, we know that this is wrong. We will improve Async.io documentation pretty much soon. And I'm going to prove you actually that Async.io is simple. You only need to know about seven functions to use Async.io every day. You don't need all this stuff in Async.io. Again, that's a toolbox. That's for framework creators.
11:01
To use Async.io, you only need to know this. So let's go over those functions. The first one, the first function that you have to know is Async.io get event loop. It returns you an instance of the actual event loop. And you have to worry about event loop when you launch the program,
11:21
but then it actually disappears. You aren't required to know about what kind of event loop you have. Just use Async.io throughout your program. That's it. So you get an Async.io event loop. That's the first highlighted line. And then you call create task. So what create task does, it wraps coroutines
11:43
into those task objects that allow event loop to actually run them. So what we have here, we have a coroutine called say coroutine function, which waits for when number of seconds and then prints what. So what we do next after we get the event loop,
12:02
we create two tasks for the same coroutine function. So essentially it will be two different coroutines. One will say hello after half a second and another one will say world after one second. And the last line is loop run forever and what it does, it literally loops run forever
12:21
until you actually terminate it somehow, maybe with control C, maybe some other way. The next function, which is actually quite important, is Async.io gather. And what it allows you to do, it allows you to wait on several coroutines simultaneously and it actually returns when all of them are resolved.
12:44
So we modified our example a little bit. Now we wrap two tasks to say hello and to say world with Async.io gather and we use run until complete. That's another method of event loop.
13:00
It accepts tasks, futures, coroutines, and it basically runs the event loop until the task is complete. So here we will end the execution when both coroutines are finished. Another important function is loop run in executor. So if you have a bunch of old code, let's say, or that uses blocking IO
13:22
or you have some very computationally intensive code, you can actually run that code in a thread or in a process pool and await on it. So it's actually quite handy. And the API itself is pluggable.
13:41
If you pass none as a first argument, it uses the Async.io internal thread pool, but you can actually pass any kind of pool executor from concurrent features module. And the last very important function is loop close. So all of our previous examples were kinda wrong
14:03
because we didn't close the loop. So the correct way is to actually run event loop and then finally block, you have to close it. The close function, close method, it actually cleans up the resources and it will print out warnings if something goes wrong.
14:21
And how, especially when you start learning Async.io, you should always use Async.io debug mode. To enable it, you can just have an environment variable called Python Async.io debug, or you can enable debug more programmatically, just call loop set debug.
14:40
It's very important to use Async.io in debug mode. It will uncover a lot of bugs in your code and it will make programming with Async.io much easier. Also, make sure that logging in Python is configured properly and you can actually see the errors in ECD out or SDR.
15:02
Because sometimes it's not and people just ask questions like I don't see any errors in program output. Async.io uses logging module, so if it's not configured properly, you won't see anything. And also, configure a test runner to print warnings. For instance, Pytest somehow doesn't do that by default.
15:22
And warnings are actually quite important. For instance, if you have a coroutine and you've just forgot to put a wait, you just use the regular function call. Then essentially, your program will do nothing because without a wait, it will just create a coroutine and that's it. It will never be scheduled. So Python is actually emitting a resource warning
15:45
if a situation like this happens. So make sure you actually see warnings. Let's quickly talk about UV loop. UV loop is an alternative implementation of Async.io event loop.
16:01
It's written in Cython and by the way, I really recommend you all to check out Cython. It's an amazing language. It looks like Python, but it compiles to C. It uses libuv under the hood and libuv is the event loop for Node.js and that's a good thing because Node.js is extremely widespread. It's well tested and libuv is really fast.
16:23
And also, UV loop defines its own implementation of futures and tasks so that even if you don't do a lot of I.O., your async await calls will just become faster. So how fast is UV loop? It's in a simple benchmark like an echo server.
16:42
It's actually quite a bit faster than Async.io. It's two to four times faster. If you have lots and lots of Python code, it won't be as exciting, but I heard a lot of reports that UV loop, even for big production applications, can give you a boost of 30, 40%.
17:04
And even if you don't have a high load on your server, I still recommend you to use UV loop just because the quality of service improves. You will have smaller latencies. So it's faster than Async.io, but it's also faster than any other Python framework on Python 3 specifically.
17:21
We are not talking about PyPy, twist, all this stuff. On Python 3, UV loop and Async.io are the fastest and the simple echo server implementation, it's actually as fast as Go echo server implementation. And it's somehow twice as fast as Node.js echo server implementation, which I personally find amazing because, well, Node.js itself uses LibUV
17:44
and itself is written mostly in C++ and C. Let's quickly talk about PEP 492. So I actually had this idea in 2014 and I quickly and briefly discussed it with Guido and Victor Steiner,
18:01
but we didn't have good arguments to actually think about this idea even more. But in 2015, I approached Guido at the language summit and I told him, let's do async await. People really don't know how to use yield froms. They don't understand that. And also, just besides doing async await,
18:22
let's introduce async for and async with because otherwise it's just impossible to write good looking code for entering a database transaction. You have to use try, finally call and rollback and manually call commit. And people just don't know how to do this. So it's not convenient. So actually, he liked this idea
18:41
and he encouraged me a lot because it was just two months before complete feature freeze for Python 3.5 release. So I spent about two, maybe five days for the first draft of the PEP. About three hours to prototype and see Python. And then I published my first draft on Python ideas.
19:02
And it was very, very positively received. So after about 500 emails and Python ideas and Python dev, we had a PEP that everybody liked. And then Nick Coghlan and Victor Steiner helped me with reviewing the patch and actually pushing it in production.
19:21
So why am I telling you all this? Is that I want you to do the same. I want you to actually, if you want something to do in C Python, some new feature, go ahead and propose it to Python ideas. Before that, please Google that this feature wasn't proposed before. And if it wasn't, just go ahead and do it.
19:42
The process from that is quite simple. You will discuss it on Python ideas with other Python users and Python core developers. If they like this idea, they will probably ask you to write a PEP, which is also quite an easy thing. We have hundreds of PEPs available now. You can read through them. You can see the common structure.
20:01
So you document your feature idea. And then there is another process. You will discuss this PEP. Then you implement this PEP or you can find some other core developer who will do that for you. For instance, the metrics multiplier operator, the at sign was added to Python 3.5.
20:21
The PEP initially was written by Nathaniel Smith, but the implementation was written by Benjamin Patterson. So you don't even need to know low-level C Python programming. If you have an exciting idea, somebody will implement it. That's it. Thank you.
20:49
Thank you very much for this talk. We have time for questions. If they are building context manager versus try-finally event loop termination thing, you showed, you say the try-finally terminate event loop.
21:03
Is there a context manager for this? No, we don't have context manager. But it would make sense to have a context manager for this? Maybe, but you use it only once in your program, usually. So that's why we are thinking that maybe it's not worth adding extra complexity to how you work with event loop. Because you can, actually,
21:21
you can only close event loop once. Once you close it, you cannot resume it. So if you use this context manager twice, it will break your program. So we decided that let's make it explicit. All right.
21:45
In AsyncIO? Maybe, yeah. Yeah, if UVloop is much faster and a drop-in replacement for AsyncIO,
22:03
why don't we just replace AsyncIO in the core Python with UVloop rather than force the users to, ask the users to replace it as an optimization? So the question is, why don't we just put UVloop in CPython, right?
22:20
There are a couple of problems with that. First of all, UVloop is written in Cython. We don't merge anything written in Cython to CPython just because we don't want to introduce extra build dependencies in CPython. So to do that, we'll have to rewrite it in C. I think it's quite doable, actually,
22:41
because when I was working on UVloop, it was actually hard to figure out how to correctly manage libuv low-level resources and Python high-level abstractions together so that garbage collection works correctly, stuff like that. I think now I actually have pretty good understanding
23:00
how to write the system in pure C, but before that, it just wasn't feasible just because it's much easier to refactor code in Cython. So to merge UVloop or to recreate it in CPython, we will need to write it in pure C and also have to make a decision of making libuv a dependency of CPython,
23:24
which probably a lot of other core developers will have some concerns with. But I think maybe eventually we'll do that. Hi, is it possible, have you published your benchmark scripts that you've actually?
23:41
They're all available at GitHub. It's a repo called VMbench. It's on the same account as UVloop. Everything is there. Benchmarks are quite generic. You have a script to run them all, and what they actually do, they launch a Docker instance,
24:01
and they launch each framework there. They warm up there in that Docker instance. So it's all automated. So you definitely can do it yourself. You can run them. Hi. Regarding the documentation issue, so if you're gonna hold a sprint on that topic,
24:23
I would gladly contribute for the basic examples because I'm really struggling with what's currently available. Sure, I would really appreciate it. I'm not sure if I will be on the sprints. If I'm not, just create an issue at Python Backtracker,
24:41
and I'll definitely take a look. Any more questions? Okay, I think that's it. Then thank you very much again. Thank you guys. Thanks.