Fear and Awaiting in Async: A Savage Journey to the Heart of the Coroutine Dream

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
it's actually great to come out to this conference I've been meaning to come for years and for whatever reason the schedule is always always been a problem one thing about this talk I guess before I get started if people haven't followed me on Twitter or they realize I had to rewrite this whole talk overnight and the reason for that is that this might be the only talk that's ever gotten a YouTube takedown notice before it was actually given and you can say okay so let me let me explain that okay so the the the topic of the talk I was going to talk about async and one of my one of the in preparing the talk I was thinking ah there's got to be some kind of theme you know like Star Wars or Mad Max or you know some kind of kind of artistic theme to the to the talk and unfortunately my my chosen theme for this was Hunter s Thompson's Fear and Loathing in Las Vegas so actually that comment about who becomes the combat drinking a section secretary okay so so uh so I came up with this talk like fear and awaiting and async we're going to talk about about co-routines and I was thinking oh there's got to be like an like this like artistic theme to this and if you if you've read the Fear and Loathing in Las Vegas book which is fantastic has these insane illustrations by Ralph Steadman in there that tell me there's like this you know it's like Harley I'm like on a drug trip or something I was thinking it was thinking like oh how could i how could i recreate that and i started looking around at all of my kids artwork around the house you know I was like oh wait a minute I have this idea because I have like six and eight year old kids right I was like oh you guys can help me out doing some doing some artwork so so they did a bunch of stuff and it was unbelievably fantastic it actually what it looked like is somebody had played Minecraft for like 12 hours and then maybe dropped acid and then and then and then went off and did like this this art project and it was like this insane stuff of like flying like ender dragons and withers and like swords and like beasts and all this stuff is if it's awesome I mean I'm looking at the talk I'm just saying oh this is this is perfect for async you know but then then you know you know kind of gets kind of near the road trip day and then somehow I got brought up it's like oh this this talk will be on YouTube and all the sundar like YouTube no way like that was it that was the end of story like we don't want the artwork on YouTube so it got shut down so I can't show you any other oregan it was so kind of kind of leaving I think there might be immoral like like don't do a project with 8 year old man it might be and maybe there's some kind of analogy to like Silicon Valley and there or something - I don't know anyway so so so what we're going to do in the talk I don't know I'm going to talk about some of the async stuff that's going on in in Python these days and essentially this is the story on this it's really about concurrency I mean it's about having programs that do more than one thing at a time and kind of the that the classic oh by the way my only alternative to make this talk just as insane without the artwork is to do the entire talk in the Python rebel so I'm going to attempt that here so so a lot of this async stuff what people are thinking about are things like servers you know network programs thing things like that I'm trying to cut to cut off the bottom of the screen a little bit so it's the people that back and see so you might have some code like that this is like a classic server with with sockets you know start with that and essentially the concurrency problem that you run into is this how would you handle multiple clients with this this code as I've typed that in I mean I can run this you know I can run a server I can say well let's go run an echo server on my my machine here and it will run that's only going to be able to handle one connection at a time so if I were to I'm you know like fire up like another window here I'm really gonna see that or not but let's say you were to fire up a I'm going to and try to connect you know it's it's basically echoing stuff back at me but then if I were to try and do another client it's going to be stuck not being able to do anything I mean I can type but it's not getting any response the reason it's not getting any response is that this first thing is holding the connection open so kind of a classic classic problem and concurrency is it's that sort of thing like how do you handle multiple multiple clients at a time and there are there are different ways of doing this one of the ways that you can do it is to use threads which I will say by the way just it's a public service unless you're implementing the next Facebook or something like that threads are actually not a bad starting point for a lot of projects like if you're doing concurrent programming and you're talking like you know maybe hundreds of clients or something like that I would probably just start with threads I mean threads work with most stuff the programming model is reasonably well understood yes you're going to have to explain to your co-workers about the Gil and other other things like that but for them for the most part threads work ok I will confess that I use threads in production if it helps you can quote me on that and maybe maybe it'll help you out I'm so so threads are one way of doing that and essentially the idea is when you get a connection fired off into a fire it off into a thread another option that you could take is to launch a process instead process what you're doing is launching like an entirely new copy of Python and then it runs independently and then you can handle multiple things doing doing that one potential advantage with processes is that you can take advantage of more CPU cores if you do that so if you know about the global interpreter lock and the fact that Python can only run on one core process is one way one way around that the only problem with this is that you're probably not going to run like ten thousand copies of Python on your on your machine here so so so you can do that a different approach that you can do for this is to start turning to async frameworks like twisted async IO the issue issue with that is that you're going to basically be taken into a completely different programming model if you've worked with these they kind of the general ideas that they have like an event loop sort of running underneath the covers so you've got this this event loop watching the network for incoming packets and coming things that are happening and then when something happens they trigger a callback function so what ends up happening is you write code where your your code is like responding to two callbacks so this is this is maybe what very simple like twisted code would look like if you are going to run that async i/o it maybe look something like looks something like that where you know you're receiving connections and responding to events and this is this is one way of handling multiple things at once you structure your whole code is this you know this sort of asynchronous model and you can handle a lot of a lot of things at once one of the reasons why somebody might do this by the way is it has it tends to be very efficient with resources especially things like memory i/o resources and so forth I mean if you need to write a program where you're where you've got like you know twenty thousand sockets open or something like that that's why people are turning to some of this async stuff more efficient than having twenty thousand threads running on your machine so that's why that's why they're doing it the issue though with this this does call back stuff though it's really the programming model programming with callback functions is not the most pleasant thing in the world I mean I do two people I mean how many people have done like callback based programming I mean do you love it I mean is it no not maybe like one hand okay so I mean it's not the most it's not the most fun thing I don't like programming in callbacks and one of the I mean you know I mean I mean we might as well just see the comment slide you know it's like you know it's like there's this kind of notion of callback hell it comes up and like tons and tons of talks it's like every single talk about async it's like some point somebody starts talking about callback hell and then and then ways to simplify that and one of the things that you've actually seen in Python over probably the last ten years maybe even longer are ways of trying to simplify some of this callback programming I mean whether you kind of layer different things on top of it like deferreds or futures or people playing around with co-routines inline functions it's all sorts of just kind of kind of kind of hacks that that people have built up and if you look at if you look a lot of that work ultimately what people would really like to have is a programming model that is a lot like thread programming but not having the resources of threads I mean they'd have to like have like a like an event thing kind of going on underneath but trying to hide that detail so really what what the what the dream would be is to maybe have code that looks like thread but it's not actually using using threads now the code that I've got up here this is something that is possible in Python three five involving async functions await statements asynchronous context manager you might be looking at this saying what in the what in the world is this this is essentially modern Python code using co-routine we're going to talk about this in a second I'm actually a little little curious before we go further how many people have played with async await in Python 3 and only like a handful okay so this is the this is the jumping off point for kind of shattering your head at this point because we're going to we're going to talk about this and so just just to see this work by the way I'll go ahead and run this okay so we're gonna just make sure that it works I'm so so I mean I'm in Python 3 I'm gonna run this this echo server oh no oh it's already in use okay well okay okay so I'm going to run that and then let's just let's just make sure that it that it works here you know he's put it on a different port okay okay there's one client okay there's another client okay so we've got two clients connected connected on that let's let's shut them all down there okay testing my I term skills here okay okay so that's that that's that's essentially code with co-routines this mean to you looks a lot like thread programming there are actually no threads involved in that there's no processes involved in that but there's this madness with all of a sudden these async functions and things like that so what I want to what I want to talk about for a little bit it's actually this notion of an async function I mean if there's anything that maybe take away from the conference to shatter the minds of your co-workers or something I would suggest just dropping this on them like you can say well you know you can you can define like an async function you know something like that and then sort of ask them it's like well what is like what is that like what is that like how does it work so this is this is this new feature first showed up in Python 3/5 define something known as a KO routine and it is very different than a normal function I mean just just to see like the difference if I write a like a normal Python function like if I say greet name like that basically you call that and it just returns the result back ok comes back and says hello Guido if I try to run that that async function like if I say greeting Guido not much happens well I mean something happened comes back and said well you get a co-routine object greeting and then you can ask well what is like what is that it turns out that these diff these async functions probably they're defining characteristic if you will is that they cannot run independently they will not execute ever on their own they have to be driven by somebody else so in order for that to in order for that to that function to work like let's say you say G is equal to Guidi Guido there somebody has to somebody has to drive it okay somebody has to drive the code I'll explain that error message in a second there and the way that these things are driven is you send them a value like you would say well I'm going to send you a value of none and then the thing will sort of run and again we end up with like a like an exception some of it comes back into stop iteration like stop iteration like what's that about okay it's like we're not even in a for loop or anything and then if you look at the look at the exception it comes back and it says hello Guido this is odd okay so the function runs it raises an exception the value of the exception appears to be the return statement out of the co-routine yeah that's how it runs actually okay so so if you have one of these these co-routines essentially you have to run it and the process of running it does look a little bit odd essentially what you have to do is you're gonna you're going to send in maybe some value I'll just set it to none for now and then you're going to catch like a stop iteration and then you're going to return the value off the exception you're looking at that thing this is crazy but but that that's how you run a co-routine though so if you have that if you want to run that that greeting thing that will do it okay so so the so the key thing co-routines it's like they don't run on them they don't run by themselves you have these async functions but they're really odd they're not like normal functions they're this crazy thing that runs under the context of iteration like that we just pause make sure everyone's kind of maybe maybe it's still not still not late enough in the day for this but it's okay so so if you got that you've got this this crazy thing here it turns out that that there that are other things that happen with co-routines as well if you have one of these co-routines it can call another KO routine without having to go through this weird iteration thing like let's say I have another facing function like like Maine for instance and I want to just let's say I want to I want to just print out the result of the other one turns out that there's this statement a weight that you can use and essentially what that will do is it will call the other Co routine as if it were just a normal function so if I were to run Maine you would find it come up and say okay hello hello Edo somebody's head is like shifting into the projector on that that side okay all right so so that that will that will run it and it turns out that you can start doing everything that you would normally do with like function calls using these these co-routines just to see another example you know like if I had a function you know like like this you could you could Wow that should have been plural at all do do something like that you can you can you can do things like this you can say okay so let's do a forward for loop and we'll issue a greeting to all of these people okay so you have a function async def using a wait we'll go ahead and run that and you see it kind of calling that other that other function like a like a well they're co-routine like a like a function so what you're what you're starting to sort of see here is that there's there's kind of this whole new world if you will starting to kind of open up with async in a way it might look like you've fallen into like a pit or so you know some scary universe but you have this D here with these alternate functions you can define these async functions you have an alternate way of calling these functions with the oh wait and doing that you can actually I mean again you can do almost everything that you would do with like normal Python functions in this sort of strange weird weird world I'm just just to give you an example of something even more strange you can do things like recursive Fibonacci numbers with async and oh wait I don't know why you would do this other than to just annoy your co-workers or something like that but I mean you could say async def fib and it could recursively call itself with like a weight statement that gives like a function that drives that and this is going to print the first 30 Fibonacci numbers out up there you could run it and it will crank crank away on that okay so it just just just did that code there's a comment up here about the slowness of this I've actually timed this it runs about two and a half times slower than normal Python function which is actually faster than I thought that it would do to be honest okay I mean it's it's a it is slower two and a half times slower okay but but the key thing it's like hmm okay and do you function stuff but it's you have these async functions you have these these these are weight function now now now now one thing I do have to to point out there is tons of Terrill associated with everything that is going on here okay so this this is a weird universe of things that that's going on first thing keep in mind that none of this stuff works if you don't run it like if I say fib 20 doesn't do anything it just comes back and says co-routine object you have to run it if you want to run it somebody has to drive it okay so every time one of these co-routines things gets gets fired something has to run it a very common mistake that is possible is that somebody might forget to awaited for instance that's another way of making it run like you could have a function where you do something like print Fibonacci 20 like that you're violating the rules that you're not running the you're not actually running the function when you do that if I run that you're going to get a weird warning message runtime warning fib was never awaited basically that means you created a KO routine but you never executed it question over here I guess I could take a question so yes Kohi so the question is that this is an excellent question where can you put that await okay so keep in mind like like just to fix the problem that I just had you have to have the oh wait in there okay so that that is the solution to the to the problems is to do that the mere presence of that though raises tons of questions about where can you put that exactly like where can you use the await one of the places that you cannot use it is you cannot use it at the interactive revel the reason for that by the way is that the interactive repple is not running under the management of like co-routines like keep in mind these co-routines have to have somebody running it the repple is not running under that and so because of that you can't wait okay so you can't do it you can't do it interactively you can also not do it in a normal function like if I had a function spam and I just said like a weight fib kin or something like that that's actually a syntax error that a weight keyword isn't even enabled unless you are in an async function so in order to do anything at all with that await you have to be you have to be in an async function okay that's that's that's actually critical about that okay so if you're in an async function you can use a weight you have to spell it right - okay okay so so that is that is okay but then you're going to do these these other questions of like well where can you where can you use it I mean we're like what are the legal places that you can use away turns out that you can you can use it pretty much anywhere that an expression is allowed in Python I mean like I mean you could you could for instance you could make a dictionary and you could use it as that you could use it as a like a key you'd say a weight fib 10 you know I mean you could do that that's okay your co-workers might want to stab you or something but you know you can use it there I mean you can use it you can use it in like arithmetic kinds of things I mean it's you know that that's okay I mean it's like that you can use it pretty much anywhere that a normal normal expression would be used no no let's just let's just print those out and just make sure that I'm not totally full of it here okay okay so that Network there are a couple places where it is not allowed one of the places where it is not allowed which frankly I find super annoying because I'm a huge such a huge fan you cannot use it in a list comprehension so that that is not going to work you actually get a syntax error I actually almost want to boo that cuz like list comprehensions are one of my most favorite features in the whole world and it's like you're getting it taken away from me it's very painful and you know cuts deep so to speak the the other place where you can't use it is in lambda like so you can't there as far as I know there's no like asynchronous lambda expression or you can't await in Al and so so there are some restrictions where you can't use it you can't use it outside of async functions you can't use it in list comprehensions you can't use it in lambdas but most other places though you can you can use it as far as writing code you can use this async stuff in a lot of different places as well I mean it's perfectly fine like in a class definition you can have async methods you can have asynchronous class methods asynchronous static methods all of that is all of that is fair game it again it is a little bit weird though like if I were to make like a spam object and then I were to say like you know s instance method it's going to come back as a KO routine and it's and it's like keep in mind that's not going to run unless somebody is either awaiting for it or it's going to run it okay so so somebody has to has to has to run the code very very interesting pardon oh let's an excellent did I pay you to lead my question okay excellent question no no this this is where things start to get kind of kind of curious it's like okay so if you have these async functions where can you use those exact like what are the contexts where you can where you can use it so you might really anticipate I have to pay em or something like that so one question could you have like an asynchronous an it function or an asynchronous Dell function or something like that in general the answer is kind of no and the reason for that is a lot of these you know the dunder methods are being triggered by Python kind of automatically because of core features and the language and those features in the language are not aware of having to run co-routines like that the fact that these co-routines have to execute on their own causes problems like I I'm actually I kind of wonder what would happen here like I mean we could we could create a spam to see what happens it's really not happy about that at all I mean it's like warning messages and then it's actually giving me a type error because an it is returning a co-routine and it's completely confused about what's what's happening there okay so so so in general special methods not going to work although you might if you I don't have take enough drugs or something I start to wonder like well maybe maybe there are places where they could be used one of the places where it appears that you can get away with using them are on any method that appears to get something this would include properties get item and get adder and various things like that I'm not going to suggest that this is a good idea by the way I mean it might be a horrible idea but if you do that what ends up happening is those attributes become like a way to Bowl attribute it's like what do you mean a way table attributes like if you were to make a like a like a spam object and then you were to say s dot value it comes back as a co-routine because that's what the get function is it was like a Co routine if you wanted to actually get the value out of it you're either going to have to await it or you're going to have to run it even my co-routines never run on their own so so in principle you could probably do this not sure it's a great idea but maybe you know I don't know it's a programming option let's put it let's put it that way you could certainly make like an asynchronous call 'evil classes have this call method that emulates a function call if you were to make that an async method you could you could certainly make that work there are other sort of more insanely evil things that one could possibly think about like could use async in a meta class and not just completely jump you know off the deep end this early but you know that that question that came up could you have like an asynchronous and it method it turns out that the answer is yes you can if you're willing to abuse metaclasses what this is doing is it's turning the the process of treating instances into an asynchronous operation and then it becomes this crazy thing where you can actually only create instances through co-routine there'll be a quiz on this quiz on this late know though this is nuts what would happen if you came up here and you said oh I want to make a spam object it would just come back saying well it's a KO routine you actually have not actually you have not created the instance yet the only way that you can create it is you have to run it keep in mind you know co-routines don't run themselves so you have to you have to have to run that I wonder what other magic is possible oh here are some kind of here's here's sort of an interesting design space to work in do people know about abstract base classes and Python this this is a class where you can you can make methods that are abstract and then it will enforce that they that they exist like if you try to create an instance come back saying well you can't do that because you didn't make the right the right methods here's here's here's sort of a thought is the presence of the async part of the programming interface like let's say you were to inherit from that like I'm gonna inherit from spam and then I'm going to implement the method bar but I didn't do it it's an async I see I see somebody cringing over here or is like we did probably the right response no this is like a weird this is like if you have two different kinds of functions existing in your language like async functions and normal functions and then they start to meet up and like inherit and some stuff this is like where you start to have nightmares right it's like okay this is insane so what could happen there well maybe you could build a I don't know maybe you could use meta classes to do like something with that you could catch it you could have it come up say no actually you screwed up you need to have that be acing it's kind of kind of odd let's see what you think about that there okay the fact that these functions have different rules about where they can be used opens up different other avenues of thoughts so so here's a here's something I was thinking about could you actually detect the context in which a function is is called here's what I mean like let's say you had a function could you determine whether it was being called the echo routine or whether it was not being called Byakko routine and turns out that you can do this you will probably pay a big penalty in code review but on if you are willing to do if you're willing to do what's known as frame hacking this is like evil there's the get frame function and people might know about that where you can look at the call frame of your call like the person who called you you can actually go up and determine whether you have been triggered from a KO routine or that so what I've got here is I have a normal function foo and it's it's basically going to say hey have I been called from a routine if I call that it will come back say no you haven't down here I have this async mein and I use this thing saying have you been called from a KO routine or not if I run that it will come back st. yes actually you have been called from a ko routine and you could say where is that going well it turns out that this opens up some really interesting things if you're willing to get into things like decorators right so you can write you can start writing decorators that rap functions and maybe start enforcing rules what is going on here is this is a decorator that basically tags a function is saying you cannot be called from go routines like this spam it says sync only if you call it from from Interactive it will come back same okay that's that's cool you you're nodding you're not in co-routines but if you try to run it from this like co-routine stuff it's going to crash saying no I'm sorry one of the reasons why you might think about that by the way I'll get to this is one one issue with a lot of co-routines concerns the behavior of blocking operations turns out if you're doing event loops and you do some operation that blocks the event loop the whole thing shuts down because there's lots of performance problems potentially you could use something like that to lock it off right I mean you could you could say look this this function is not safe in code routines you could tag it and it will not be called in go routines now you're going to have to explain to the Python gods why you're using a frame hack for this and that's but that's a whole different different issue but that but you can do that some other possibility this is this is a kind of a by even more insidious thing maybe you could have the same function name but do different things depending on whether you're in co-routines or not so so what I've got here is I have a function spam which normally says if you call that it comes up and says all your the your the blue pill because that's that's like a normal function but then there's like this weird away double version of it that if I if I call that from like a like a co-routine like I say a weight span it comes up and says well you're the red bill I don't know whether this is like completely insane or not to have like the same function like you have ass function spam that works one way in one context but another way in a different context I see more cringing up in the up in the up in the front here so it's uh it's fun stuff it gets better than this by the way there is um there is something known as asynchronous iteration like asynchronous iteration what is that well what you can do is you can write iterators like you can say this this is something called a countdown and you can do what's known as an async for loop an async for loop I was like what is that essentially what this is doing is it's giving the iteration protocol an option to call co-routine like you can call other co-routines and the next and the iterator method again to run that okay so nice messed it up I'm not going to I'm not going to type it in again just in the interest of time but you can you can do asynchronous iteration there there's also an asynchronous with statement like you can have like a like a context manager that uses a enter and a exit I mean what is what is that what this is about is you can you can make a manager just call it em like that and then you use an async with statement hopefully this will work okay I've redeemed myself a little bit there okay so so so you're looking at this I mess up so first of all I guess I mean they're quite okay we're kind of scoping out a little bit that like the space of these async functions okay you have these async functions they can be used in a lot of different ways like they can be used as methods functions some special methods there's things like asynchronous iteration and and and so forth and you can I guess maybe the question that comes up is like why like why are we going into all like what is going on here other than just creating like this insane weird world so so in thinking about the why one possibility might be this you want your co-workers to hate you and I found this quote online this this son this blog by the way this there's this blog what color is your function it's actually an excellent post by the way that talks a little bit about what we're just what we've just been doing here it talks about this idea blue functions and red functions and some are async and well and so forth I would definitely recommend reading that but I think that the bigger picture of why is really this going back to like a lot of this network code this IO code let's say you have some function like receive on a socket why do you care about that well let's let's talk about this for a second if you do an operation like that it's ultimately going to involve some kind of system call it goes down into like this like the C library and does a system call somewhere if it's making a system call at some point it's going to talk with the operating system kernel and then the operating system kernel is just going to block everything because you're waiting on a network interface for some packet to show up okay so you do an operation like i/o it's going to go down into the system it's going to block okay so this blocking this is really the whole point of everything because this is why people are using threads and processes I mean this is the thing that prevents concurrency is the fact that your Python program blocks and then everything is like shut down so you you you end up with this this problem of how do you get around that that is the that that is the problem the ultimate problem now kind of riffing on this figure a little bit more one of the things that you that you might know about system is that there is a fairly strict separation between the two spaces that you're operating on here kind of up at the top this is the world of Python and C programs and applications you have user space and then down below you have kernel space which is you know that's the operating system and and so forth one thing about that kernel space you never see that as far as far as a user like you know if you're up in user land you're not really looking into the into the kernel you might also know that getting into that kernel space usually involves a special operation either a trap or an interrupt or something it has to do with getting you into protected memory mode and other other things so there's there's there's essentially these two spaces that that are that are existing there's a way of getting from one to the other and the reason that I'm talking about this is that this async stuff that we're doing it's kind of the same you have async space and you have normal space if you will or synchronous space and what's going on is that when you're working with async functions like this you know a sink in a way you're kind of up in this like this world of you know async function and so up up there you have your code like that this kernel space in some sense is kind of like that run function keep in mind that co-routines never run themselves they're always running under the supervision of somebody else it's kind of what kernels do like in an operating system it's like they're running code they're supervising your code so so this this model from like an operating system where you have like user space and kernel space maybe that's kind of what we have going on here we have async space and we have synchronous space the question though is what sits in between there has to be a way of getting from one to the other and this is really kind of the magic trick the way or the bridge between those two worlds is through Python generator function that's why that that involves like a stop iteration and other things so somewhere in the in the system there is something that that gets defined with the yield statement that that is basically the magic that that makes this whole thing work and the reason that that is that is that is the magic is well let's talk about that for the reason that that works it's the essential feature of yield is that it causes your your function to basically stop like if like if I do that like let me let me let me just try this out here okay let's say you have from an import types let's say we do types co-routine I have a title on that slide by the way so forgive me okay so let's say had that and let's say you had a yield yield in here like like that let's say I were to have some function that called that somehow like let's say I had an async function we have async may main like that and I just said like a wait a read like oh wait read no three 1000 so something like that and then what I'm going to do is revise the run function just slightly here one of the things that I want to that I want to do on it is actually just print out what got yielded on this thing because this this is kind of the same the same the same run function as we had before what's going to happen is if I run that main what what will happen is it will run but it will hit the yield statement I'll just sort of stop it'll just say well you yielded read and now we're back at the prom it's like the co-routine ran and it's sort of just sort of stalked midstream so you have this magic trick it causes co-routines to stop and the reason that people care is that that is the mechanism for getting this concurrency to work it's the way that people get this cooperative multitasking to happen is through that that yield statement that is what is driving it and having seen that I'm going to pose this question should you even care about this I mean do care what should you care and I've given a lot of talks about generators and co-routines and things over the years I mean I gave this kind of famous co-routine tutorial and so forth I'm looking at this async stuff I'm looking at that tutorial and I'm thinking should I care at all about that tutorial at this point and I'm not sure that I should maybe as an analogy do you care how a cynic how a system call works on Linux I mean how many people in here have actually cared how a system call works on Linux I mean unless you're writing like an operating system I mean like me is a C programmer or a Python programmer I do not care how that works like and yes it loads registers and it does a trap and so forth I have never once had to think about that ever like in writing an application and I sort of wonder like if you're going to go into this magic world of async in a way do I ever have to care at all ever about this this facet of it yield generators I don't know the reason the reason why I bring this up is I want to talk about some of this other async stuff is there any reason for me to ever care about event loop or callbacks or futures or transports or protocols or any of that stuff more specifically do I need to worry about what is going on in the async i/o library if people looked at at async i/o it's a new library showed up in Python 3 4 it's been around a little while if you look in there there is a lot of stuff going on I mean we could do the help on it it's going to be nasty because it's auto-generated but it's got like co-routines and event loops and queues and transports and protocols and tasks and futures and all of this stuff and I guess my question is do I care do I do I want to care about that and I'm not sure that I do and and so we're gonna get into the last part of this talk it's really this question can I program async and ignore all of that can I ignore everything in async i/o the same way that I can ignore how a system call works on way but can I stay at a high level maybe another way of thinking about this is can you flip the narrative on a sink a little bit specifically this this is what is if you if you go back and you and you watch like Guido's talk on a sink i/o and things like that one of the things that they talk about in there is this idea of having an interoperable event what can you have these different libraries like twisted and tornado and G of n so forth can they operate on the same event whoo essentially the problem is if you're working on one of these async libraries they have to have an event whoo and it's hot you can't have like three different event loops running that's the problem and and so there's this idea of an inter interoperable event loop can you flip this whole thing to do this this this is kind of what I'm thinking about it's like instead of the interoperable event loop could you have like an interoperable API doing a sink and a weight and if did could you run your code on just whatever event loop that you wanted without worrying about it kind of the same way that I could take like us program and run it on Windows and run it on Linux as long as they both have like POSIX functions or something you know it's the same kind of same same same kind of idea so this is this is something that I've been kind of playing around with in a project for the last eight months I don't want necessarily want this to be a plug for this project but I've been working on this curio library which is a it cut in in some sense it's like an experiment in seeing whether you could just go all co-routine in fact you've actually already seen the main interface to this library it provides one function that is normal which is the run function and that is basically it okay so you can write async functions and you can run them that is actually the only part of this library that does not work out that that works outside of co-routines the entire rest of the library is pulled completely into co-routine trying to do absolutely everything in the co-routine universe turns out that that that this code that i had earlier this is this is that was running on curio like this a sync server kind of code that we that we had earlier there are simpler versions of that that you can simplify this is also cure curio code it looks very similar to things that you might write with with with threads and so forth and part of the part of I guess kind of the experiment of trying to do this okay so you know I sometimes I ask myself like okay why in the hell am i writing an async library I mean it's like like it's like you'd be like I'm going to rewrite Emacs or something I mean there's already a lot of like you know async async' libraries out there I guess part of the experiments just to see what it looks like to program all in co-routines like just to see if this can even work at all about your head just shattering basically okay so part of that part of the experiment is that part of its just to see like does it have performance I mean like is this even a good idea or anything so I thought it would talk about just a couple of like like facets of it that that have come up one of the ways that this library operates by the way is it tends to put wrappers around things what you tend to do is you use ordinary objects like files and sockets and so forth and then what you end up doing is you replace you replace them with like wrappers that go around it essentially the purpose of these wrappers is to do asynchronous stuff so like like what I've got here is I've opened up a pipe to some command using the sub process module I've taken the two files on that and put like a wrapper around it like this standard in comes back it looks like a file object but if you try to do anything on it it will come back with codeine everything is a Co routine okay so you want to do anything at all you have to stay in the co routine world okay so so you can run that up one of the one of the things that that have found in doing this is that a lot of the programming actually does read in a fairly straightforward way I mean this is this is something that communicates with that sub process just kind of talk about what it does it's it's spawning a task to read all the data off of standard out then it's doing a time out then it's writing data then collecting data off of a task it's it's a short amount of code it's something that can often be understood another thing that is going to come out of this project is that the performance of it has been way more than what I would expect it this is this is an example of some benchmarks with this curio project just putting it up against some different frameworks including G of n twisted and async IO what we're doing here is it's like a 16 core linux server it's got a bunch of bunch of tasks just like hammering the server as fast as possible and seeing how fast it go it's not bad almost 50 thousand messages a second on this like curiyo async only cured like co-routine thing we're up above G event G event uses a C extension okay so I mean it's like it's it's kind of shocked to be honest one thing that is new by the way there's a this project UV lube which is a async i/o it's its re-implementation of the async i/o event loop using libuv which i think is used by node and definitely not as fast as that if you want to stick in callback functions but if you're doing co-routines this curio project is still pretty still pretty fast so some interesting things there but I don't really want this to be like a like a curio talk per se I'm what I really want to talk about we're getting near the end is I want to go I want to go back to this code okay so this this is this this a single weight code that was used in the in the curio example and I guess like the question I would pose on that is where are the dependencies on a library in that code like like twisted or async IO or like import statements where are the import statements in that code what I have is an async function it's using a weight it's not really using anything else and in the coin I guess the thought that that I have about this is that it couldn't that code run on a whole bunch of different things like like wouldn't you know again this interoperability could that exists at the async await instead of the event loop doesn't matter who runs that code does it matter that it runs in curio doesn't matter that it runs in async IO I don't know did do the details matter at all I think that you could actually probably adapt that to make it run on async IO it's an interesting idea people have done this sort of thing in Python before with things like whiskey the database API things like that common API so why couldn't we have something with async away it's an interesting idea so so those are the thoughts now the challenge is if you're going to do this we're getting near the end I think I have like what five minutes lambda guy so so let's say you wanted to do this I think the first challenge is just is this async/await stuff even a good idea to begin with I'm not so sure after the earlier discussion of like the asynchronous meta classes and so I saw something like cringing and like scared looks but like the part of the point of doing that was just to kind of scope out the whole world of that a single weight and what's possible you have this whole world of stuff is that sane or not I don't know okay I honestly don't know so that that's that's one challenge the other challenge if you're going to do it is just what makes a good API in this async world having experimented with this there are all sorts of holes that one can fall into that are very scary well I'll give you an example one debate that I've had in the in the curio project is whether to make clothes an async method or not one argument is that well clothes doesn't really do anything so just make it normal but then you get these other cases like well it could be a file and maybe the file is like buffering up a bunch of data and then when you close it it has to flush the buffer out somewhere but when it flushes the buffer out somewhere it could block because you know blocking i/o and then like the close method blocks and then like your whole is that loop is stalled okay so that you maybe you should make it a Singh but then you can make an argument it's like well maybe it should just be async on files but not on sockets that's crazy because then it's like synchronous in one place but not in the other so you have like no it you have like no consistency right so it's like lots of lots of tricky stuff there another another tricky part is they I think if you're going to do this you have to keep the event loop out of it one one complaint that I have with async IO is that it requires the event loop to be carried around everywhere if you use that library you'll find it kind of everywhere I don't think you need it when you're working with co-routines you know who's running the code whoever is running the code is running the code it like knows what the loop is can simplify it the other the other challenge is I think you have to go all-in if you're going to do I oh it's everywhere it's sockets its files its directories pipes sub-process these timers the whole universe anything that blocks is going to destroy your event loop I was actually talking with somebody recently they were talking about it at work they're rewriting a Python project and go I'm sure that nobody has heard this recently right it's like okay rewriting Python and go and I say well why are they doing that well they're using G event but there's some kind of weird performance problem I was like oh what's the performance problem they're like well under load this thing gets really slow and it's like so init digging a little bit deeper and okay so they're using G event but then what they were doing is like normal file i/o like just with the open function in the code I mean if you know about files it's like okay you open up a file I mean that can go out and hit disk I mean it's like we're talking like rotating platters verbs you know whatever it's like you know the hole that your whole universe go it grinds to a halt for like five milliseconds or something and they're wondering like why the thing is slow it has nothing to do with G event it has everything to do with the fact that they're doing this stupid synchronous i/o operation in the middle of it so if you're going to do this you have to go all in however that's however that's going to work okay I already already did that one okay so so as far as closing closing this thing off I think there's some opportunities here if you're looking for just a cool insane thing to be working on a single wait is where it's at I think I mean there's there is a lot of like weird stuff first of all you'll shatter the heads of all your co-workers they're gonna look at your Co and they're just be like like what is that you can also forget about any version of Python prior to 3/5 so forget about porting or backporting or he's like no okay so you don't don't have to do that the other the other thing I thought it would plug here you have to look at what's going on in the protocol world this is Cory Ben fields work doing HTTP to one of his things that he's been promoting is that IO protocols should be decoupled from IO and he has this this hyper h2 library which implements HTTP to that library is totally agnostic on the IO model like whether using threads or async I view with curio it's a really cool project you should definitely check out as PyCon talk because it is kind of taught it is sort of in this same space of like where do you where you draw the line on implementing some of this stuff so so that's done that is basically that's basically it the end of the talk um I don't really have any final comments other than you know this this async/await stuff it's a very odd strange universe and python if you're looking for something fun to work on get involved with it so I'm I think that did I just got this zero minutes so they're gonna kick me off kick me off here so thank you very much you
Info
Channel: Next Day Video
Views: 25,280
Rating: 4.9578948 out of 5
Keywords: pyohio, pyohio_2016, DavidBeazley
Id: E-1Y4kSsAFc
Channel Id: undefined
Length: 56min 47sec (3407 seconds)
Published: Wed Aug 03 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.