Async Techniques and Examples in Python Transcripts
Chapter: Built on asyncio
Lecture: Concept: Mixed-mode parallelism with unsync

Login or purchase this course to watch this video and the rest of the course contents.
0:00 We've seen mixed mode parallelism. It's something you could easily run into. Do you have to do some work where some of its computational
0:07 and some of it is based on I/O either explicitly through asyncio or just because it's talking to a network or a database or something like that?
0:15 How do you put that work together? That's not super easy and that's why we started talking about unsync because it solves this problem exactly.
0:23 So, here we're not using unsync. This is the asyncio style and we're going to create event loop.
0:29 Again, that event loop is actually hard to get ahold of and pass around if you're passing this through tiers of your application
0:36 or down into another library or something like that. So it looks like no problem here but it can actually be a challenge in your architecture.
0:43 Then we're going to create a bunch of tasks so we can't just call compute_some or download_some_more because those don't return values
0:49 those return coroutines, OK? So we've got to create a task from them and queue them up like that using loop.create_task.
0:55 But, more importantly, where should these run? Compute some, give it obvious names, kind of giveaway names but compute some is CPU-bound.
1:05 Download some more uses asyncio. When we wrote this we decided, hey, some of these functions can use asyncio, so let's go that way.
1:13 Let's just go and do this work in asyncio. And for the green ones, download_some_more and wait_some that's a good choice.
1:19 But download_some, that one is implemented in requests it's API is. So there's no way to really take advantage of it here.
1:26 It's just going to block things up. Effectually that part becomes a serial thing, not parallel. Similarly for the compute_some, it should be run
1:34 probably in multiprocessing. But how should we know that, as the caller of the function? Maybe we didn't implement it.
1:39 Maybe we're using it from somewhere else. How do we know? That's, kind of, not great. So we have to make this decision, how shall we run it
1:46 and actually, truly mixing together is not super easy, either. And then finally we have to create this loop
1:52 we got to use the loop and call run til completed at the end and gather up the tasks and so on. And that's not great.
1:58 So let's see how unsync solves that. We have that top block where it says tasks. That's the entire previous slide.
2:06 Well, that and the list comprehension to block but it's not up to us where we're calling it to decide how our code runs.
2:13 It's up to the implementer of that function. Who wrote that function, they decide where and how it runs.
2:20 So the compute_some, that one's going to run multiprocessing. Download_some_more, asyncio, download_some on a thread.
2:27 We don't know or care about that really at all. It's just going to work, as far as we're concerned. There's some future, it's running, when it's done
2:36 it's done, do it the best way that you can. And the way we indicate that is we have either regular or async methods.
2:43 So, like, compute_some and download_some those are not async. One of them is just regular unsync and that means run on a thread.
2:50 The compute_some is unsync and CPU-bound which means run in multiprocessing. And that just happens automatically above
2:57 when we create that list of tasks. We don't know or care about that it's all transparent. And finally, at the bottom, we have an async method
3:05 that is unsync, that means run on the ambient hidden, asyncio event loop. Beautiful, right?

Talk Python's Mastodon Michael Kennedy's Mastodon