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