Python tricks: Demystifying async, await, and asyncio

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Biggest thing I don't like about async await is the drumming in the heads of people that say over and over "it's not another thread" when the only times it's not another thread are if it's an I/O routine. Almost always any work you do of your own will be in another thread even with async because it will be a CPU and not a hardware operation. So I think to keep insisting on that "no thread" just confuses people more about how async works

👍︎︎ 1 👤︎︎ u/MetalSlug20 📅︎︎ Aug 04 2019 🗫︎ replies
Captions
hi my name is first yamato and today i would like to talk to you about async await and async IO in Buyten now what is this all about well let's first talk a little bit about difference between synchronous and asynchronous code which is not all that complicated synchronous code is just the kind of code that you're probably used to and it's the kind of code that runs one function after another so each time that a function is called we wait until it's finished and then we call the next function etc that is synchronous code now a synchronous code is goat that runs multiple functions seemingly in parallel now why seemingly well because we are not making use of processes right we're not making use of multiple processes actually running in the operating system we're also not making use of threads right which are sort of sub processes that run within a single process rather everything is happening within one thread and one process what we just very rapidly alternate the functions functions suspend and then another function takes over then that function suspends another function resumes etc etc and this gives it gives the appearance of running things in parallel without any kind of resources and complications that you have with threading and multi processing now in order to run asynchronous code you need to write code that is explicitly designed to be asynchronous so you need to write well-behaved functions and specifically these functions need to occasionally explicitly resume in order to give other functions the opportunity to take over and run themselves right so it is kind of cooperative multi processing style could say now also very important in asynchronous programming you should never use blocking functions for example time don't sleep it's blocking function which just pauses the execution of your program until the sleeping time is over and that will completely break the asynchrony because it will mean that every function has to wait until the timing of sleep is finished and the same is true for things like doing network communication with the socket module etc instead you need to use particular functions that have been designed specifically for a synchronous asynchronous programming and the async i/o module provides a lot of those funky for example I think il has a sleep function that is an alternative to the kind of sleep function so it's an asynchronous alternative and we will see that here now quick note on Python version so the async and the await keywords which I will use in this tutorial we're introduced in Python 3.5 but I think IO module was introduced a little bit before in Python 3.4 and essentially everything that you can do with awake and async can be done with a little bit of a different syntax using the async i/o module but with Python 3 2 3 or earlier versions you cannot do this at all you can approximate some of the techniques using generative co-routines which I won't talk about but essentially before Python 3 - 4 you could not do this kind of asynchronous program now let's get to work what are we going to do as a sort of dummy code i would like to use a function that determines the highest prime number below a certain value and we're going to do that three times for three different values so we create a main function main right that's going to be the entry point to our program and I'm going to assume that there is a highest prime below function below and first we're going to do this for 100,000 and then we're going to highest prime below for 10,000 and finally we're going to do this for a highest prime below for a thousand and then we call our main function here right now of course I still need to define this highest prime you love function so death highest prime below nothing special around this is just completely synchronous ordinary code how does that work well let's first print out the debugging message because then we can see we can kind of follow the flow of our overcoat when we execute it so print out highest Prime below up the X and then what we're going to do is for Y in range X minus 1 until until 0 with steps of minus 1 so we're going to is going to decrement from X minus 1 down to down to one and then we're going to say if is prime why print out that we found it right so we print out okay the highest prime below this is step X comma Y and we're going to return Y and then what I'm going to do to kind of simulate it this is a to kind of simulate a problem with blocking blocking functions I'm going to do with time dot sleep of 0.01 so sleep for 10 milliseconds the import time module right so this could be this is kind of a obviously it's useless here but it kind of demonstrates what happens when you have blocking functions such as time not sleep but also network communication in your code now if we don't find any prime number we simply return them then we still need to have a function that determines whether something is a prime number that's a little bit interesting problem how can you do that well you can do it in many ways and probably I have no idea how to do it most efficiently but what you can do for example is return if it's not the case that for any X divided by integer divided by I equals x float divided by I in other words if the infant you're division of X by Y I sorry is the same as the float division in other words if X is devel advisable by by by I then it is not then it's obviously not a prime number right because X should not be divided by I if it's bright and then for I in range X minus 1 2 1 1 in steps of minus 1 okay so that is a way to determine if X is a prime number right nothing really matter if you cannot float follow the logic here although it's a nice exercise so we decrement I from X minus 1 down to 2 and then we check if X is divides both by I and if it's that's not the case for any I then it's prime that's logical now let's see if this works so just run it up yes this works and you see the synchronicity over code right because we first call highest Prime belong 100,000 up it returns does its calculation it returns then we do it for 10,000 returns we do it for a thousand it returns etc so this is purely synchronous now let's gradually make this code asynchronous right asynchrony is not an all-or-nothing thing we can kind of gradually make it asynchronous although code that is partly asynchronous and partly synchronous can be a little bit inelegant right it's not an ideal situation but it's possible so as a first step towards a synchrony we simply say that main is an async death it's an asynchronous function if I now run it up you see that it doesn't crash it's still valid Python but main doesn't do anything rather it's a KO routine object why is that well that's because asynchronous functions are not intended to be called like that there has to be either awaited and we will see that later if they will have or they have to be passed to the event loop and the event loop is an well program software that takes care of all the asynchrony right that manages which functions executes when etc now where is this event it's in the async IO library and then we where so where is it well the event loop is in async IO dot get event loop and then we say loop dot run until complete main right so it's pretty simple we get the event loop and then we run this function in the event loop until it's complete easy peasy normally you would say loop goes close when you're done I'm not going to do that here because if I do that in this interactive I bite in a terminal it will break things but normally you would do that if you would do it in the script now let's run it so this runs again but you see it still behaves exactly in the same way as our synchronous code does right because we call our highest prime below with 100,000 then with 10,000 and then with a thousand now and we have not explicitly we have not designed our function to be well behaved right we have not made any real changes that that improve the timing that that allow our code to become asynchronous so what can we do well we can say okay we also make highest Prime below a synchronous so we say okay this is asynchronous if I now run it I will get a warning up a runtime warning co-routine highest Prime below was never awaited that's because here I'm I'm kind of trying to call this asynchronous function but that's not the way to do it right you either have to pass it to the event which we've already done or you have to await it so I say oh wait oh wait oh wait if I now run it it's still it still works but it still does exactly what it did before it's still not really a synchronous why not well because we've not given our program any explicit points at which to to basically suspend the function and have another function take it over right we simply await this until it's finished then we await this until it's finished and then we await this until it's finished but that is not a synchronous right it is some it has some asynchronous syntax in it but it is not in terms of it's not logically asynchronous so what can we do how do we actually make this asynchronous well we can the first step is by instead of waiting each of these functions in turn synchronously we can say okay I await not these functions but async IO does wait and this function a think I out of wait takes the series up takes the series of coroutines up so a list of goroutines right a list of asynchronous function calls and it's executed and it waits until they're all done now if I execute this up it will work and this is already slightly asynchronous in the sense that we have lost control over which function is called first right you see in this case now the highest prime below thousand is first and then 10,000 and then 100,000 and if I call it again it will use a different order so there's an element of randomness in here which is inherent to asynchronous programming so we have we have some asynchrony but it's still still not really really asynchronous because each function is executed then we wait until it completes then we call the next and then we wait until complete and then we call the next and wait until completes so how can we make this really asynchronous well the trick the magic trick to making a function really asynchronous is to adding somewhere in the in the function a point where you say ok now I'm going to suspend and this can be here if we say instead of time not sleep we say the wait async i/o dot sleep 0.01 then we tell our event loop or we tell our function ok now suspend hand over the hand of a processing time to the event loop and the event loop will then activate another function that will run for a little while it will suspend another function will resume around for a little while will suspend etc etc right so here by by adding this await async I'll go to sleep function we have made our code well-behaved we have made it through the asynchronous now look at what happens to the here if I run it you will see up now we launched all three functions but instead of waiting for each function to complete before the calling the next function you see they all complete more or less this at the same time and that is that is a synchrony in action right so we launch all functions then we eat all the functions while they're running they suspend here with this await statement giving the other function calls the chance to resume and do their work etc so they all start working seemingly in parallel but really in very rapid alternation until they're all done more or less at the same time and it will print out the result to the to the debug window right so this is this is truly asynchronous code now and then you will see red just to show you the difference if I activate time to sleep you will see it will become synchronous again because it is really this point where we allowed function to suspend that that implements the asynchronous aspect of our code now another thing that is can be relevant in some cases is execution speed so let's find this say okay p0 right is time to time so I get it I take a timestamp from before we calculate all the highest primes that time stand for afterwards time to time and I say print up this took 2f milliseconds now so I need to multiply by a thousand right because time will time return seconds not milliseconds and then I say t1 minus t0 okay if I run this you will say okay took 584 milliseconds and to see how stable this is do it again up 591 right so let's say slightly less than 600 milliseconds now if I remove this asynchronous aspect so I I comment out the awake async I'll go to sleep and introduce the regular sleep both of which are sleep functions that sleep for 10 milliseconds and if I run it you will see now it takes 695 right if I run it again even 740 so about 100 maybe 150 milliseconds slower than our asynchronous implementation now why is that well that is simply because this async il dot sleeve is not working rather what it does is simply say okay suspend the function allow the other functions to run and about 10 milliseconds later take that control and resume right so the 10 milliseconds that is spent sleeping is not spent for the computer just completely being idle rather it is spent with the other functions doing their calculations and so you have a little performance getting now here the performance gain is very small but if you're working with socket contrite with network communications with sockets where for example sometimes you have to wait a long time until server responds for example then you can get really massive important if performance improvements here now ok I hope I've been able to explain how async await an async il works in a nutshell they are not that difficult asynchronous functions are simply functions that alternate that are execute executed in very rapid alternation in a way that makes them parallel but it's really in the same process and without any threading and if you want to write a synchronous code you need to make sure that your code is well based so that it you awaits functions for example using await async I out of sleep so that other functions can take over and you should avoid blocking functions because they will cause enormous performances now thank you very much for your attention [Music]
Info
Channel: Sebastiaan Mathôt
Views: 80,325
Rating: 4.9205899 out of 5
Keywords: python, tutorial, screencast, async, await, asyncio, programming
Id: tSLDcRkgTsY
Channel Id: undefined
Length: 15min 59sec (959 seconds)
Published: Thu Aug 03 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.