Async Techniques and Examples in Python Transcripts
Chapter: async and await with asyncio
Lecture: Faster asyncio loops with uvloop
0:00 I want to highlight a project
0:01 that can almost effortlessly make
0:04 your asynchronous code faster
0:06 and the project is called uvloop.
0:09 So, uvloop is a reimplementation of the asyncio event loop.
0:16 And it turns out that the way Python was built
0:19 that asyncio event loop can be replaced with others.
0:22 And so the async and await keyword can run
0:24 on different implementations of that IO loop.
0:28 And this happens to be one of them
0:29 so it's a quick drop-in replacement
0:31 for the built-in asyncio event loop.
0:34 It's implemented in Cython, and uses libuv.
0:37 So Cython is basically Python compiled
0:40 to native optimized C code
0:43 and libuv is a lower level library
0:47 that is an event loop for different languages built in C.
0:50 And if you look here, a quick claim here is uvloop
0:54 makes asyncio 2 to 4 times faster.
0:58 So here you can see built-in socket behavior versus
1:02 over here, that socket one, that's quite a bit faster.
1:05 Or protocol versus this protocol
1:07 it's actually a little hard to figure out what goes where
1:09 but these are all the native standard behavior speeds
1:14 and these are if you just do this quick drop in.
1:17 So how do we do that? Well, it's not too hard.
1:25 So let me show you a simple little program
1:28 that I built. It's a little bit fake, but that's OK.
1:30 So it's going to come on here and it has a limit
1:33 of 250,000 items. I guess we could make it more obvious like this.
1:38 And it's going to use the async event loop
1:40 and it's going to run, and run, generate
1:43 generate, and process. And now what we're doing is
1:46 we're not doing hardly any sleep.
1:47 We are sleeping a tiny, tiny bit but we're just saying
1:51 "give up our time slice and let something else run
1:54 but then immediately pick us up, and keep going."
1:56 And we're doing this 250,000 times.
1:59 So what we're doing is, instead of having a few
2:02 big blocks that we're slicing our work up into
2:05 like previously I think we had 20 things we produced
2:09 and 20 things we consumed, and each one had two
2:13 sort of waiting points, so at most we broke it
2:15 into 80 slices. And those little slices were executed
2:18 over a period of 21 seconds.
2:21 Here, we're going to take a quarter million slices
2:26 executions, twice, actually we're doing this here
2:30 so maybe 4 times that actually.
2:32 So, what is that, a million times 2
2:34 so that's a couple million slices running
2:36 as fast as we can.
2:37 And when we have things that fine-grained
2:39 very, very quick and fine-grained
2:41 then we start to see the behavior
2:44 the actual performance of the underlying asyncio event loop
2:48 itself come into play.
2:51 So if you just have a few coarse-grained slices
2:53 this is like, not required, right?
2:55 But if you're breaking things into vere fine-grained bits
2:57 that run for very short periods of time
2:59 maybe this technique is going to be helpful for you.
3:02 So let's run this real quick.
3:04 We have a standard version and a uvloop version
3:06 and we'll do the uvloop from scratch.
3:09 So here you can run it
3:10 with two times the quarter million actions.
3:13 Now we wait, and it takes 8.7 seconds, OK.
3:18 So that's how long this one took.
3:20 Let's go and do the work to implement our uvloop version.
3:26 Now, we're going to have uvloop as a dependency.
3:30 And we're going to need to install that here.
3:32 I don't think it's installed.
3:33 Let's go to our terminal and say pip install uvloop.
3:37 Spelling is hard. OK, that worked.
3:41 Now all we have to do is we have to import uvloop
3:46 and we have to say asyncio.set_event_loop_policy().
3:52 Event loop policy.
3:53 So basically this is telling asyncio
3:57 when you create your event loop
3:58 use UV's event loop implementation. That's it.
4:03 We haven't had to touch our code or anything.
4:05 We just have to run that at startup
4:06 and let's see how things work now.
4:13 4.7 seconds. 8.7, 4.7, and all we did
4:18 is change the underlying implementation.
4:20 If this kind of stuff is going
4:22 to give you a big improvement
4:23 go ahead and take the dependency on uvloop.
4:25 You're probably depending on other packages anyway.
4:27 It's really awesome.
4:29 Like I said, if you're breaking it up
4:31 into very coarse-grained things
4:32 you know, it probably is not worthwhile.
4:36 But it's such a easy performance win
4:39 that if it helps you, you should definitely think
4:41 about using uvloop.