Async Techniques and Examples in Python Transcripts
Chapter: Built on asyncio
Lecture: Demo: Converting from asyncio to Trio
0:00 So we'll begin this Trio exploration
0:02 by just duplicating this.
0:03 So we'll copy and then paste it back here
0:06 and I'll call it prod_trio.
0:09 So let's go over here and again I told you
0:11 this is not built on asyncio and actually
0:12 it's not even compatible with it without
0:14 that bridging library so we're not going to do this.
0:18 We're not going to do that stuff so let me comment out
0:21 and we'll delete it in a minute.
0:23 So, instead of having a asyncio queue, we'll have Trio.
0:27 And notice there's a pycharm warning saying this initializer
0:30 this constructor takes a parameter that we're not passing it
0:33 and that is the capacity has to be set.
0:36 The capacity's job is to say
0:38 remember when you tried to put stuff into the queue?
0:40 Down here, we were seeing
0:42 await putting items into the queue.
0:44 Well, how do you know when it's just going to put something
0:47 in a queue versus we want this to stop filling up
0:49 the buffer and stop producing items?
0:52 Well, that's what this capacity is.
0:54 This is how many items can be put into the queue
0:56 before it blocks when you call put. Let's say 10. Okay?
1:01 And then all of this stuff, we're going to take all of this
1:04 and we're going to simplify that dramatically.
1:07 So the primary construct that you'll see in Trio
1:11 is this thing called a nursery.
1:13 The nursery spawns children tasks
1:14 and you know, that's the idea there.
1:17 So what we're going to do is we're going to convert
1:18 main into an async method.
1:21 It's going to take one more adjustment
1:22 for this to actually work, below but we're going to convert
1:24 that to an async method and we're going to say
1:25 async with trio.open_nursery() as nursery:
1:33 And then recall we want to run that twice
1:36 and then produce so what do we do?
1:38 We say, first, we spell nursery correctly
1:41 and then we say nursery.start_soon().
1:44 Now it doesn't give you auto-complete
1:46 which is kind of annoying.
1:48 So we could do, just do this real quick.
1:51 Complete. We could import this and then start_soon
1:56 start, start_soon, cancellation scopes, all sorts of stuff.
2:00 So, we'll go in there and what goes in here
2:01 and we pass a function and then a *args
2:04 and a name as a keyword argument if we want.
2:07 So and that's pretty cool.
2:08 We're going to pass this and just the name.
2:11 There's the function.
2:12 And then we pass argument one, argument two
2:14 and then if we want we can have the name
2:16 for debugging purposes, Producer 1.
2:19 We're going to have another one, do it again.
2:22 And then we're going to have this processor
2:24 this consumer, and this is 40. There we go!
2:31 Well, now what else do we have to do? That's it!
2:34 We're actually done. So here's how it works, and let me get rid of this
2:36 'cause this is just so you could
2:37 sort of see the auto-complete list.
2:39 What we do is we open a nursery within
2:42 an async with block, so this awaits here.
2:45 And then we kick off all of these tasks.
2:48 So start_soon queues them up
2:50 and internally these could themselves write code
2:54 like this that would open child nurseries
2:57 and they would also basically become child tasks
3:00 or we could pass the nursery and those could also spawn
3:03 more that are sort of independent of these and so on.
3:06 So we're going to kick all of this work off
3:09 and then this with block will not be exited.
3:11 We won't get past line 18 here
3:14 until either it all completes successfully
3:17 which will be probably the best case
3:19 or one of them gets an error
3:21 in which case any still running ones
3:23 get canceled and then we exit the nursery.
3:26 Or we can do timeouts which we'll talk about later.
3:29 All right so, this looks a lot simpler, right?
3:31 Don't have to do this, all these weird hoops
3:34 we're jumping through, we don't have to do that.
3:35 Now, again, we converted from a asyncio queue
3:38 to a Trio queue, so we got to do that down here.
3:42 And we don't asyncio.sleep, we trio.sleep.
3:47 But other than that, pretty much all the same.
3:51 Don't need that, okay. Let's run it and see what happens.
3:53 Oh, yeah, did I tell you there's one more thing to do?
3:55 RuntimeError. What does it say?
3:58 Main was never awaited and we exited right away.
4:00 So down here in order to run this coroutine
4:04 which is now it is a coroutine
4:06 we just need it to say trio.run
4:07 in a synchronous context like this.
4:09 Now our app can run.
4:11 So it should operate pretty much the same as it was before.
4:14 Well, in fact, basically exactly the same
4:16 as the asyncio edition. And there it is!
4:21 Pretty much exactly the way the asyncio edition ran.
4:24 There's a few things that are simpler.
4:26 Up here we're not really taking full advantage
4:29 of Trio because of all of the networking capabilities
4:31 that it has for like writing
4:33 our own server and stuff like that.
4:34 But, you could check out the docs.
4:36 They have a cool, like, network TCP echo server
4:39 if you want to see how that's done.
4:41 This is pretty simple.
4:42 I'm not sure it's simple enough
4:44 to justify switching from asyncio to Trio.
4:47 But, I'll show you some more features of Trio
4:49 that make it really powerful.
4:51 Maybe do make that switch worthwhile.