Async Techniques and Examples in Python Transcripts
Chapter: Built on asyncio
Lecture: Why do we need more libraries?

Login or purchase this course to watch this video and the rest of the course contents.
0:00 Before we get to the programming details of these additional libraries let's talk about why we might need them at all.
0:06 We have async and await. We have threads. Isn't that good enough? Well, it depends on what you are trying to do.
0:13 Yes, it's good enough, but it can be better as we all see. So what are some of the shortcomings of the various aspects that we've worked with so far?
0:20 Mostly around asyncio, but also around threads and processes. One of the things that's annoying about asyncio is
0:26 you have to have an event loop in order to execute an async function. Remember what we did is we created
0:33 a loop, and then we queued up a bunch of work in it and where we created some coroutines and we said run to completion or something to this effect.
0:41 And we waited on that loop. And it's not that hard honestly, but if you have a deep architecture:
0:48 some function, calls another function, calls a library which called another function, how do you take the loop
0:53 you have to create at the outside and pass it deep down to the inside so async functions down there can run?
0:58 If you need to coordinate across those things this can be really not so easy. Alright, you end up passing stuff around or having
1:04 weird global variables that, depending on how things are working, may actually not even work.
1:09 This is a shortcoming, and we'll see if one of the libraries we talk about fixes it. So this is the shortcoming, and each of the libraries
1:16 we're going to talk about has a certain way to address this. Asyncio.future is not thread-safe. Now, that may sound weird to you, but remember
1:23 asyncio doesn't actually use other threads. It's like an event loop on a single thread so it's not thread-safe.
1:29 But if you want to mix it with threads, that would be better if it were, right? On the converse side, we have concurrent.future.
1:37 Remember this comes back from the ThreadPoolExecutor or ProcessPoolExecutor? When we queue up work, that thing cannot be used with
1:44 async and await. It cannot be directly awaited which is annoying. Wouldn't it be great if I could get one of those back and mix it in and await on it?
1:53 Well, you can't. Future.result is a blocking operation. It's generally good. If it's not done you want to get the work back.
2:01 However, if you're doing this in an event loop you could actually clog up the event loop and if somehow there's a loop you somehow create the future
2:10 which is running the event loop and then you call a block on it on another slice of those tasks running there you will deadlock your event loop.
2:17 Not great. On the other hand where future.result is a blocking operation asyncio.future.result will actually throw an exception
2:26 if you haven't completely waited for it to be done. So, depending on which type future you have it doesn't behave the same, that's also hard
2:34 so we'll see of unifying stuff happening here. Async functions, as in async def - that's a function name
2:40 always execute in asyncio loop. They don't run in threads. They won't run in multiprocessing mode. None of those types of things.
2:50 However, may we have some work, and some of it is based on asyncio, but other parts of that work that we're trying
2:56 to do altogether might be computational. Or maybe it's working with something that talks to a database or network, but that library doesn't support
3:04 asyncio directly. It would be nice if we didn't have to completely have different API's and ways of working with them
3:11 if we could unify that. Well, cancellation and timeout are tricky things than threads and processes.
3:18 Thread local storage, which we have not talked about does not work for asyncio concurrency. So thread local storage is kind of like a global variable
3:26 but each thread has its own copy of that data. Each thread has its own values for that global data. Imagine something like Flask.
3:38 Flask has a global request object, and each time a request comes in, you can just access it out of thin air
3:45 in your view method. And it has the value of that particular request. And that's fine if it's single threaded.
3:51 You can just set that value, do the function call and then unset it. But remember, asyncio has only one thread for all these
4:00 interwoven operations. So thread local storage no longer means what it used to mean. Well see, none of the libraries here directly address this
4:08 but further down the line when we get to the async web stuff that's one of the problems that's going to have to be addressed.
4:15 Testing concurrent code can also be tricky. These are some of the shortcomings that the libraries we were talking about will help us address
4:23 and they also bring their own cleaner programming API for certain things that they're built for: coordination, parent/child tasks, things like that.


Talk Python's Mastodon Michael Kennedy's Mastodon