AsyncIO and the Event Loop Explained

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I've done a couple of videos about concurrency and Python's asyncio package before asynchronous programming is really useful especially if you interact with apis and I wanted to Revis this subject so I thought let's have a slightly different take this time so what I'm going to do in this video is dive deeper into how asynchronous programming actually works behind the scenes using an event Loop talking about events I recently was at Pyon Lithuania which was a lot of fun it's a really great meeting everyone one of you even gave me a pair of lithu socks if you were the person who gave them to me thank you again they're very comfortable actually I'm wearing them right now look anyway if you want to learn how to design a piece of software from scratch while you're in excruciating pain check out my free designu at iron. cdesign guide this teaches you the seven steps I take whenever I design a new piece of software hopefully it helps you the link is also in description of this video ouch and I'm feeling much better again it's amazing asynchronous or concurrent program means that you can run CPU bound operations while you are waiting for iob bound operations what are iio bound operations well for example waiting to read a file or waiting to get a response from an API request or a database or serving a web service so in short what that means is that you can with concurrent programming for example launch a multiple AI calls concurrently you don't have to wait for one to finish in order to launch the next one or you can do other things while you're reading a file or if you building a server you can serve multiple clients all at once if you have that capability if you integrate concurrent programming properly into your software then your software is also going to feel snappier and I mean especially nowadays applications interact with apis or databases like all the time so doing things concurrently can make a massive difference in your user experience in Python we have the async io library for that and even in the latest python versions 3.10 3.11 3.2 there's still been updates to this Library so this is changing and improving all the time now concurrency is typically built with an event Loop that manages asynchronous tasks and this allows the execution of multiple tasks seemingly in parallel but actually this all happens within a single thread take a look at this diagram we have the script that creates the event Loop and then adds tasks and the event Loop then starts executing these tasks so there is a loop that basically goes over all of these tasks and checks whether they have been completed and if so that task is being marked as completed so the script can basically continue doing other things while the event Loop takes care of the tasks and then finally when all the tasks are completed the event Loop is closed so that's in principle how this works in older versions of python I think Python 3.4 and before you have to actually do these things explicitly you see an example of a script that shows this so I'm importing the ASN KO package which is used for concurrency and they have a couple of functions do iio and do other things now do iio does nothing except caller sleep function but as you can see in the main function I have to actually get an event Loop and then call run until complete on these functions and then I have to explicitly close the loop that's how you have to do things in more recent versions of python this is actually way simple you can just call ASN ko. run and then you pass the function that you want to run in this case I'm calling that on the main function which is a concurrent function that's what the async word means in front of the function signature now get back to this example in a minute here I have a very basic example of a server that hosts a server on local host on Port 3000 this server has very basic implementation us a socket but most importantly it runs synchronously and that means that this server can serve only a single single client at a time it can serve client B if it hasn't finished processing the request of client a and that just means that this server is going to be incredibly slow it's not even that stable because I even think it's quit with an error if a second client tries to connect when the first one is still being processed so it's not really a great solution let me show you what I mean so I'm starting the server here and I have a little test script here that calls the URL several times concurrently so when I run this you see that we get some sort of client connection error and here actually Al the server crashes now that might also be for different reason I didn't really do a very good job of building a very stable server but handling client request sequentially on a web server is simply not a very good idea and this is also one of the main reasons that Frameworks such as fast API all use asyn iio because that's just a much better solution so here I have another version of that same server except that now it's asyn and that's not just because we changed the class name actually I'm using here a syo and you can see that methods like starting the server are asynchronous and I'm using asyn kio's start server function for that and that's typically also how you can see easily that some code is concurrent because it uses the async and await keyword so async is to indicate that something can run concurrently and a wait means that within that concurrent function method we wait until a particular task is completed before we continue with the next one so here of course we want to wait until the server has started to actually uh get the socket and logging that the server has started makes sense right and then we call the serve forever now what does this serve do actually not even all that much it simply handles basic requests and it serves an index.html file which is simply a local file that I have defined here and that returns an image that's base 64 encoded so let me start the asynchronous server like so and then when I open the browser we see that we get a beautiful image of me and some sort of server help but most importantly because this server cannot handle requests concurrently our test server script now runs without any issue so let me try that again so we see that it now serves these requests so each takes about 2 seconds and that's mainly because I added an ASN K sleep here of 2 seconds so if I let's say um put this in comments and then let me restart the server so now the server is restarted and when I run the test again you see that the requests are now handled really fast one thing in particular that you notice in this asynchronous version of this basic server is that we also using some asynchronous packages like IO files for example so um I'm using that to in order to generate response I'm using that to open a file in this case that's just than HTML file and honestly I wouldn't recommend you implementing a server like this yourself there's many great Frameworks out there I've already mentioned fast API but other examples of great Frameworks to use are D Jango or quartz now when you actually look at this diagram that's sort of representation of how request is handled in our asynchronous server so you see we have client that connects to the server the server then accepts connections that's handled by the request Handler the request Handler has process request and process request then handles the request generates a response returns it and we go back until we reach again the client who then finally gets the response and what asynchronous programming allows us to do specifically is that we can overlap this sequence of function calls and that allows us to perform the iob bound operations of reading files and serving sockets while we perform cpub Bond operations like routing validation Etc and that's what makes handling quests asynchronously a way better solution than handling them synchronously now you may wonder why do we need async IO why not just use threats well in Python specifically threading has lots of limitations due to the gild global interpreter lock and that hinders true parallel execution it's not the case of course for all the languages but another thing is that threads have a very different kind of API than ASN the await and async keywords are really helpful for handling these types of concurrent requests if you have to start a separate thread yourself for each of these things that's going to lead to a lot of boilerplate code now async iio resolves this Global interpreter lock problem in Python because it enables concurrent execution without using multi-threading and that makes single threaded applications that have IO bound tasks way more efficient and like I mentioned this dramatically increases performance if you're building a web server if you need to read multiple files if you need to interact with apis and and so on and this all works via this core event Loop combined with other things such as cues now like I mentioned in the asynchronous server I'm using some libraries in particular AIO files to read files asynchronously and that's an issue that you're going to encounter more often in Python unfortunately most python packages don't really have great support for concurrency and that means that next to the basic packages that are part of the Python standard Library you're going to have a bunch of libraries that provide concurrent version of these things that are then slightly different so the python ecosystem at the moment in my opinion doesn't really serve concurrent programming all that well I would much prefer if the standard libraries in Python had better support for this but unfortunately at the moment that's not the case so we have this kind of fragmented environment that we have to deal with you see another example of where that plays a role so let's say you're building an API that interacts with a sqlite database happens quite often where you have some local uh database that you need to interact with and using SQL lights just I don't know to store some settings or do whatever you want to do but if you want to do like currently you can't use the build in sqlite you have to use another package in this case I'm using iio sqlite to do that and then when you have that your API server can use ioq light asynchronously to connect to let's say a database and then execute some sort of query right so what we've done in this example you can by the way just get this example by going through the examples get repost if put the link in the description of this video we've basically implemented most of the crud methods so there is getting books getting movies adding books and movies uh deleting them the basic things that you would need in an API and when I start the server I create the necessary tables and what's interesting about this piece of code is that I'm using the ASN KO task group feature and this is similar to ASN gather I'll show you an example of that in a minute so it allows you to start various tasks concurrently but it has better functionality than gather gather is simply to use but task groups have much better functionality allowing you to uh deal with cancel tasks or uh you can use it together with exception groups so that exceptions are properly propagated properly propagated properly propagated so you can handle them uh as you see fit and with Galler this just doesn't work all that well and by the way if you like these types of very technical discussions you might also like my Discord server go to disc IR codes to join there's lots of people there very knowledgeable it's really great community and I hope you also join us now I'm going to start this API server so again this use exactly the same URL and Port just for testing right but then let's also run the async API ciance which is this file that then calls a bunch of these API requests concurrently in a batch and this uses a. gather because we don't really care about canceling task or dealing with exceptions in this case so started the server right here and now I'm going to run this API client and you see it adds these uh books and movies and delete them again as we expect and again because the standard request function from urel doesn't support concurrency we have to use a special library for that I'm using ioh HTTP here because all the libraries in this code example sty with iio so why not but as an alternative you can also use httpx which also supports concurrent HTTP request so now I'd like to hear from you how often do you rely on concurrency to make your code be more Snappy and are there particular libraries that you like to use do you agree that the python standard Library should have better support for concurrency or are you okay with using these other libraries instead let me know in the comments so in this video we've talk about the difference between synchronous and asynchronous code I've talked about a few libraries that I'm using to help support that and showed you a couple of examples of how you could incorporate this into your apis I really encourage you to experiment with this and see if there are some areas in your application where you can apply concurrent programming to make your code more performant now if you want to learn more about asq and get some useful tips on how to get started doing that watch this video next thanks for watching and see you soon
Info
Channel: ArjanCodes
Views: 24,023
Rating: undefined out of 5
Keywords: event loop explained, asynchronous code, asynchronous code in python, async code, async code in python, asynchronous code python, asyncio, asyncio python, asyncio python tutorial, asyncio tutorial, event loop, event loop python, python event loop explained, asyncio event loop, asyncio event loop explained, asynchronous programming, python programming, synchronous programming, python asyncio, python asyncio tutorial, python programming tutorial, concurrent programming
Id: RIVcqT2OGPA
Channel Id: undefined
Length: 13min 33sec (813 seconds)
Published: Fri May 03 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.