Async Techniques and Examples in Python Transcripts
Chapter: Built on asyncio
Lecture: Demo: unsync app for mixed-mode parallelism
0:00 Are you ready to use unsync? Let's go import it.
0:07 From the module we're going to import a decorator
0:09 that we need to use. Now, let's just see a couple of things
0:13 that are, let's say, annoying here.
0:17 So first of all we have to create the loop
0:19 and like I said, it's fine when it's all right here
0:21 but if you have a tiered application
0:23 and different layers of your app need access to this loop
0:26 all the sudden that's annoying that this exists.
0:28 Why can't there just be an ambient asyncio loop
0:32 that is the event loop for this thread, for this program?
0:35 Boom, there is now.
0:37 Second, why do we have to call create task on this?
0:41 Can't we just call this function?
0:43 Like, why can't we call these functions
0:45 like we can regular functions?
0:48 We can, that's what we're going to do.
0:50 So now we're capturing our tasks
0:52 and if we didn't actually care about the return value
0:55 or waiting til everything was done we don't need to do that.
0:57 But we do want to wait til they're done.
0:58 So we don't need to create the loop
1:02 call, you know basically add this work into the loop
1:05 and then wait on it there.
1:07 But we do want to, actually, wait before it
1:10 so it's done, right. We saw how we did this with threads.
1:13 We said t.join() for t in threads.
1:17 So we're going to do something similar.
1:19 We'll get our value.
1:23 And this we're just going to call the results.
1:26 Remember in unsync when we talked of like
1:28 the beginning, this a blocking call until it's done
1:32 rather that some kind of exception that it's not done.
1:34 So this line will basically make everything wait
1:37 and then we can print it out. So this is step one.
1:40 Basically we're removing all the junk
1:42 that we had to add for doing asyncio, right?
1:45 Remove the loop, remove the adding the work
1:47 and so on, and we're just going to wait
1:48 kind of as if they were threads, I guess.
1:51 Now this is where it gets interesting.
1:53 So we're going to go and we're going to add this unsync decorator.
1:59 Here, here. Any of these functions we want to treat this way
2:03 we're going to add unsync to them.
2:05 Now, this is how the rules work.
2:07 If the unsync decorator is applied to an asynchronous method
2:12 it is going to run an ambient
2:15 you don't have to create it but it will be there
2:16 asyncio event loop. This is all good.
2:21 We don't have to do anything to make this work.
2:22 This will make it run in an asyncio loop.
2:26 This one, however, it's not really an async method is it?
2:30 It has the word async here, so we could mix it in
2:33 into our API, but there's no await.
2:36 So let's take away that, cause it's not really meaningful
2:38 to have it be that.
2:40 We can still apply the unsync decorator to it
2:42 and what that means is
2:43 when unsyc is applied to a regular method
2:46 it will run it in the background as well
2:48 but on a thread, not on a asyncio loop.
2:52 Async method, asyncio loop. Regular method on a thread.
2:57 Similarly, this one async. No other comments
3:01 no other values passed. Run this on asyncio
3:05 exactly as it should be.
3:07 Now finally, here we have another sort of fake
3:11 not useful async method, so turn it back to this.
3:14 Running it on a thread, does that help?
3:16 No, we've already seen no, that does not do anything.
3:19 It just makes it more work.
3:21 So unsync has a great way to deal with this.
3:23 You say, this one, this operation is CPU-bound.
3:28 When you say that, it's going to say
3:31 "Ah, here's a regular method.
3:32 I would have run it on a thread
3:33 but it's CPU-bound, so we're going to run
3:35 that on multiprocessing." That's it.
3:39 Multiprocessing, best option for that one.
3:42 This one, can't remember which it is, sorry.
3:46 That one's async, so that's going to run asyncio.
3:49 That one does not have an async interface
3:53 so we're going to run that on threads
3:56 but cause it uses network it'll still release the GIL.
3:58 And that, again, asyncio.
4:02 Let see if it works, let's run it and see
4:04 if it does any better. Damn, look at that.
4:10 Sweet, let me make it bigger and we'll run it again.
4:13 So, run it one more time.
4:16 All that's going at once, all of it.
4:19 All the computing all the downloading
4:21 some of the downloading on threads
4:22 some of the downloading on asyncio
4:24 and all the waiting on asyncio
4:27 all at once. And then we just had to wait
4:30 for the computation to be done
4:31 and for the downloading bits to be done.
4:34 So let's look at the output.
4:35 Started out with 9.6 seconds cause there was no parallelism.
4:39 That was bad.
4:40 We added what we knew, what we chose what we thought
4:44 might be the best option for this particular situation.
4:47 Said, "OK, so let's try asyncio."
4:49 We have a lot of that in play
4:50 and that's really the most efficient
4:52 if we can use it.
4:53 So let's try that, we got just under 5 seconds.
4:56 We threw unsync where each method
4:58 knew about its internal implementation
5:00 the best way it could be run
5:03 and we got this beautiful 1.3 seconds.
5:07 Really, really nice.
5:08 That's unsync in a nutshell.
5:10 There's not a whole lot more to it.
5:12 We basically import the decorator
5:15 and we just call the functions.
5:16 We don't care if they're async
5:17 not async, whatever, we just call them.
5:20 They all return these unfutures
5:23 which we talked about at the beginning
5:24 and then you can get the results
5:26 and wait on them and so on.
5:27 And then we just indicate here's a CPU-bound up
5:29 regular function, here's a not CPU-bound async function.
5:35 So, asyncio. Here's a regular non-async function
5:40 so threads, again, async, regular function, asyncio.
5:45 And that's it.
5:46 I think this is a beautiful simplification
5:49 of this whole API and it brings it all together
5:52 in a really, really great way.