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:20 So let me show you a simple little program
1:23 that I built. It's a little bit fake, but that's OK.
1:25 So it's going to come on here and it has a limit
1:28 of 250,000 items. I guess we could make it more obvious like this.
1:33 And it's going to use the async event loop
1:35 and it's going to run, and run, generate
1:38 generate, and process. And now what we're doing is
1:41 we're not doing hardly any sleep.
1:42 We are sleeping a tiny, tiny bit but we're just saying
1:46 "give up our time slice and let something else run
1:49 but then immediately pick us up, and keep going."
1:51 And we're doing this 250,000 times.
1:54 So what we're doing is, instead of having a few
1:57 big blocks that we're slicing our work up into
2:00 like previously I think we had 20 things we produced
2:04 and 20 things we consumed, and each one had two
2:08 sort of waiting points, so at most we broke it
2:10 into 80 slices. And those little slices were executed
2:13 over a period of 21 seconds.
2:16 Here, we're going to take a quarter million slices
2:21 executions, twice, actually we're doing this here
2:25 so maybe 4 times that actually.
2:27 So, what is that, a million times 2
2:29 so that's a couple million slices running
2:31 as fast as we can.
2:32 And when we have things that fine-grained
2:34 very, very quick and fine-grained
2:36 then we start to see the behavior
2:39 the actual performance of the underlying asyncio event loop
2:43 itself come into play.
2:46 So if you just have a few coarse-grained slices
2:48 this is like, not required, right?
2:50 But if you're breaking things into vere fine-grained bits
2:52 that run for very short periods of time
2:54 maybe this technique is going to be helpful for you.
2:57 So let's run this real quick.
2:59 We have a standard version and a uvloop version
3:01 and we'll do the uvloop from scratch.
3:04 So here you can run it
3:05 with two times the quarter million actions.
3:08 Now we wait, and it takes 8.7 seconds, OK.
3:13 So that's how long this one took.
3:15 Let's go and do the work to implement our uvloop version.
3:21 Now, we're going to have uvloop as a dependency.
3:25 And we're going to need to install that here.
3:27 I don't think it's installed.
3:28 Let's go to our terminal and say pip install uvloop.
3:32 Spelling is hard. OK, that worked.
3:36 Now all we have to do is we have to import uvloop
3:41 and we have to say asyncio.set_event_loop_policy().
3:47 Event loop policy.
3:48 So basically this is telling asyncio
3:52 when you create your event loop
3:53 use UV's event loop implementation. That's it.
3:58 We haven't had to touch our code or anything.
4:00 We just have to run that at startup
4:01 and let's see how things work now.
4:08 4.7 seconds. 8.7, 4.7, and all we did
4:13 is change the underlying implementation.
4:15 If this kind of stuff is going
4:17 to give you a big improvement
4:18 go ahead and take the dependency on uvloop.
4:20 You're probably depending on other packages anyway.
4:22 It's really awesome.
4:24 Like I said, if you're breaking it up
4:26 into very coarse-grained things
4:27 you know, it probably is not worthwhile.
4:31 But it's such a easy performance win
4:34 that if it helps you, you should definitely think
4:36 about using uvloop.