Async Techniques and Examples in Python Transcripts
Chapter: Built on asyncio
Lecture: Demo: unsync app for mixed-mode parallelism
Login or
purchase this course
to watch this video and the rest of the course contents.
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.