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