Python 3.11: A Guided Tour Through Code Transcripts
Chapter: Concurrency Improvements
Lecture: Barrier Introduction and Demo
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
we're going to look at another asyncio feature that might take a little bit of an example to get your mind around. I want to use a game as an example.
0:11
So in games we often have this core set of operations that has to happen each frame that goes on the
0:18
screen clearly you want to say take what the scene looks like and draw on the screen but there's more to
0:25
it. Maybe there's a little bit of time has changed and you need to reevaluate the physics.
0:30
Has this moving thing bumped into some other solid or moving object,
0:35
in which case they have to have some change applied to their direction or it has to stop or it falls You might need to update the physics of the world.
0:44
If the users are entering input on a control or on a keyboard, you need to take that they realize they push the button.
0:51
What do you do in the button buttons pushed and you take some action there,
0:55
maybe there's AI features running around and some of these things need to be done in a certain order.
1:01
Some of it can be done up ahead. You gotta wait for steps and then more.
1:05
So for example, drawing the screen, you might brought the screen to some invisible part of some sort
1:13
of virtual, non visible screen and then as one final step, swap it. Otherwise you could see the screen drawing.
1:21
You know, usually on a really fast game. That doesn't happen but you get flickering and tearing.
1:26
Maybe you don't see the drawing exactly, but you still do get these artifacts that are not great.
1:30
So we talk about this game loop, there's a bunch of different things.
1:33
Part of them has to happen. We all get to this kind of the frame is done and then we
1:38
do what happens for the rest of it. So here's a cool little example that talks about using py game
1:44
down at the bottom. There's this section you can see to start the game and just create one and we just say game.loop over and over and over again.
1:52
But how do we coordinate those different operations if we were to say, scale them out using async Io because maybe they're talking to external systems,
2:02
like a database or we're using asyncio. On the file system or we're just using threads, however,
2:08
we're coordinating them. How do we use these asyncio mechanisms to facilitate that?
2:15
So let's go write some code here. We'll start with another new project kind of game. Like, I suppose I'll say in sync with barriers.
2:22
So here we have our async method which is our game loop,
2:27
and we're just going to say while true until someone exits the game and breaks out of this list. Well, we want to do a couple of things,
2:34
we want to compute the physics, get the input and render the scene.
2:38
Of course we could have more right. We could have the ai side we could have networking going on if
2:44
we're doing multiplayer, all sorts of different steps here, but we basically want to group this into, here's the start of a frame,
2:52
We're going to run them all together so check this out.
2:54
We got our asyncio task group gonna run all the frame tasks when they're all done and we can consider
3:02
the frame finished and start that loop over again over and over.
3:06
Hopefully 60 120 frames a second, incredible how much computers can do when you really think about it,
3:12
especially in the context of games here. However, right now we don't have a great way to organize it so look coordinate it. So we're here,
3:22
we're going to do some work to print the screen and this is just simulating it 1.5 seconds and then we
3:29
want to somehow wait for the other parts, like the physics and the networking and input all to happen and
3:37
then we're going to do some cleanup work and carry on. Imagine that takes a little more time. Similarly, we're going to compute the physics,
3:43
wait for the frame to render and then we could do another, you know, some other work to wrap that up. Same thing for input. Right, well let's run it,
3:52
see how it works. It's going if we stop, what do we get here? Looks like the timing is good enough that they're not weirdly out of order or
4:03
anything, but we do better. We say soon as maybe we don't need to do one of these sleeps
4:10
with them. As soon as the work is done for one of them make sure we let it go. So that's where these barriers come in and here's how it works.
4:18
We're going to create a barrier. It's going to be an asyncio .barrier three now again doesn't look like it exists does it?
4:29
But guess what? It runs just fine. Why? because the same bug that PyCharm has with exceptions and 3.11 it also has with asyncio.
4:38
I don't know what's up but don't worry about it. So down here we're gonna pass each one of these functions.
4:45
A barrier and notice three here and three tasks. So the way the barrier is gonna work is if you
4:52
try to go and interact with it you can say wait for the barrier to be all complete one task does it great. It's gonna wait a second task does it?
5:04
It's gonna wait But as soon as the third one says I'm done and waiting all three of them together will
5:09
be unlocked. All right so let's get in here and say that this takes B Which is an asyncio barrier And this one takes one and this one takes one how do
5:26
we use them? See where it says pause here and wait for the other task we just see.
5:30
b.wait now. That is an asynchronous task right we want to let other async work happen
5:38
while this is waiting. So we await b.wait right now that's one trigger. It was just going to pause and do it again here.
5:49
That's two waiting. But we said the barriers for three things so when two are waiting there still must be
5:54
one going and then we say that here now that will be the third one when they all hit they all
5:59
unlock this one will run that asynchronously. This will run that asynchronously and this one will run that
6:05
asynchronously let them go see how they're all waiting done, waiting done instead of just popping out randomly at whatever time it is.
6:14
You can see them coordinating the beginning runs, they all get finished and then all the cleanup runs,
6:20
beginning all the cleanup, beginning all the cleanup. Very very nice.
6:27
Now of course if this was a game you would hope this is an incredible slow motion because this would be
6:34
you know seconds per frame not frames per second but of course it's going slow.
6:39
So you get the idea all the work starts, they make some progress till they get to the point where
6:43
they need to wait for the other sections to be done and then they're all released once every single one of
6:49
them is done. Super cool. Huh? Not a real common thing that you have to do but if
6:56
you're gonna fork off a bunch of work and you need to know how far they've gone and at some point
7:02
like, okay, we're waiting here until the rest of it gets done, that we can do some more work on that same asyncio task.
7:08
Well, here you go, barrier, it's for you.