 Please give him a warm welcome. Is the microphone working? Yeah, OK. OK, so I wrote this talk out of anger and frustration because I was wondering what all the fuss is about about the new async features in Python 3. And I had no success in learning these new features because I was confronted by a thicket of new words and new concepts, and it's hard to tell where to start. So I felt like this character. I'm familiar with Python 2, but I just know Python 2. So how do I make the transition to the new world of async? So the goal of this talk is to do as much as we can with just Python 2. Kind of take the simplest possible problem and just implement it in Python 2, and then make the connection to Python 3. It is not a tutorial on how to write async code in production because that's way beyond the scope, but I hope it does prepare you to study further. And the really important goal is to develop a mental model to know how to think about async. So async is concurrency, and the whole point of concurrency is that programs often just stick around and do nothing. You're waiting for network requests to finish, you're waiting for a file to be read and written, so often the programs, they just wait for something to happen, and that's I.O. And the idea of concurrency is that you can do other stuff while you're waiting. So that will use the CPU in a more efficient manner. Async is one way of doing concurrency. It's single-threaded, so you don't have to worry about all the exotic problems, very thorny problems that multithreading can involve. So it's really easy for you to control the order of execution. It's just how programs normally work. One line runs after another line. And even better, the really good news is that you probably already know async. If you have done any JavaScript, you know that there's a function called setTimeout. This is a screen card from the Chrome JavaScript console. What setTimeout does is tell JavaScript to execute a function at some duration later. So in this example, the first line says, please print goodbye after waiting a second. The second line says, print hello after waiting half a second. And you see that in the output, hello prints out first, even though it's the second line that's executed because the delay is less. It's half a second, and then after a whole second has elapsed, goodbye prints. And what JavaScript does is that the setTimeout functions puts the callback onto a task list. And JavaScript has an event loop that continuously checks every item in the task list. And when it sees that the expiration has elapsed, it will call the callback, and that's it. That's how async is possible in JavaScript. So let's do this in Python. So my first attempt is to simply write my own sleep function. The function sleep, all it does, is it has a while loop that just checks whether you've reached the expiration time. I know that sleep actually is a function that you can import, but just for fun, I wrote it myself. And the setTimeout function, the second function, that's basically a copy of the JavaScript version. It takes a delay in units of seconds, and it takes a callback that will get called when the delay is reached. All right, so this is actually live code. This is Jupyter Notebook. So I'm going to define these functions, and then I will set the timeouts and see the result. Unfortunately, this does not work, because goodbye prints out first, and the reason is quite simple. The first function has to finish before the second function is even reached. So in other words, this code is blocking. The first function blocks the second function. So this absolutely is an abysmal failure. All right. So the key idea that we need is generators, which fortunately we've already seen earlier. A generator is basically code that you can pause and resume. And the idea where generators can be helpful is, imagine you have several generators in a list of generators. You can take turns. You can go through your generators and execute them one by one a little at a time. So this is possibly how we think about multitasking, is you have a bunch of tasks, and you just do them incrementally one after the other in a circle. So that's the idea. All right, so this is a quick example of a generator. This is a regular function, except it yields, and so it returns. And then the function outputs not the result, but something called a generator object. And we've seen before that the way to get results out of the object is to pass it to the next function. So the first time we call next, we get the first yield. And now the generator object is frozen, so we can call next again, get the second value, the third value. And once we've reached the end, if you try to call next again, you get the stop iteration exception. And we also learned a moment ago that you can put a generator inside of a for loop and iterate over it. So this is just a for loop, and it does what you expect. All right, so back to our task. How do we make the code work now asynchronously? Well, we made some small modifications. The sleep function before was just an ordinary while loop that doesn't do anything, and the function will finish when you reach the time, the expiration time. Now what it does is, if you have not reached the expiration yet, it simply yields, and it yields none. So if you are before the expiration and you try to get a value out of the generator, you get none out, and it's still in progress. And then you can move on to the next generator. And then this version of the set time out function, before it was simply sleeping for some time and then moving on to executing the callback at the last line, now what happens is, it will take values out of the generator one by one and yield that thing until the sleep generator is exhausted, and then it will call the callback. So this allows the execution to be incremental. All right, so let me define these two functions. And we see that we'll just have to do a test case. We'll do a print, high, after two seconds. Of course, nothing happens yet. It's lazy. We'll have to pass it to next. And because it's a two-second delay, I have to keep clicking. I have to keep executing next until I reach two seconds and then print out high. And then now I can no longer use it because generators are only one-time use. So let me do this again. I'll grab another generator. And now I'll just quickly keep executing this cell. And you see that after two seconds, it gives the result and finishes. So at this point, what you can do is, you can just rapidly click on the cell. And then everything is synchronous. But the problem is, most programs, you don't get the user just to keep clicking on something. That would be a very bad UI. So what we need to do is we need to do it automatically. We somehow need to automate this process of keeping getting things out of the generator. So this is where the event loop comes in. That's the job of the event loop. But Python, unlike JavaScript, doesn't have a event loop that comes with Python. So we'll have to just make one. We know how to make loops. This is a very simple version. This function takes a list of tasks. And as long as the list is not empty, it takes the first task out of the queue out of the list. That's the pop zero. And we'll simply try to get something out of the task. The send none method is really the same thing as calling next on the task with an uninteresting difference. So just think of that as next. And then if that generator object has been exhausted, we'll see the stop iteration exception, upon which we'll simply do nothing. That task is finished. We'll just forget about it. But if we don't reach the stop iteration, that's the else clause. We'll put it back into the task queue, but at the end of the queue, so that we'll make sure that we'll process every task in turn. So we'll define this function. And now I will create a list of two set timeouts at one and a half second delay. And we want the hello to show up first. Indeed it does. So now we've replicated the behavior that we expect coming from JavaScript. So what does this have to do with Python 3? Every line I've written so far, you can execute in Python 2. You should try this when you get home. I promise that it works. What Python 3 does, it introduces new syntax. And it introduces a new part of the standard library that gives you a lot of utilities for dealing with asynchronous input-output. But really, the ideas were already inherent in Python 2 in the form of the generator. All right, so async.io is the new module by Python, I believe, 3.5 introduced. We'll just import it. And the way to use it, really, there are just tiny cosmetic differences between this version and the previous version. One difference is that the generator function sleep now needs to be decorated with something called a code routine. This actually doesn't do much other than telling Python that this is a code routine rather than a normal generator. So think of it as a cooler version of a generator, but actually under the hood is no different. The bigger difference is that the setTimeOut function now has this funny new keyword in front called async. So whenever you see async def rather than just def by itself, you know that this function doesn't return a normal value, but it will return a code routine. So it's really to help you distinguish between normal code that happens to generators from async code. It keeps your concerns separate. And then the only other difference is before we had to consume the sleep with a for loop, now we use this more succinct syntax that's called await. And await what it does is, well, we'll just wait for that sleep generator to finish before we move on and call the callback. It's just to consume that object. All right, so now we'll give this new version of our asynchronous code to the same run function that I defined earlier. And really, it works just as before. There's no discernible difference in behavior. And it's just to help you convince you that there's nothing new under the sun. This is all just window dressing. All right, if you don't want to do yourself, you can use the event loop that has the sample of approval by the Python Software Foundation. And it comes with the async IO library. And you call the function getEventLoop. And it gives you a nice event loop to deal with to use. So we'll just do it. And then there's another function called gather, which basically packages up your asynchronous functions. And then it assembles it into a list of tasks. And then we can give this list of tasks to the run until complete method that's part of the event loop. And it does what it sounds like. So just run your code until everything is exhausted. So hello, prints. And then another half a second later, goodbye, prints. To summarize, async and wait, the syntax is actually independent from the library. And that was a big confusion for me. It turns out that async IO, the module, predates the new syntax. So they're completely independent. And you can actually use libraries that other people have written or write to yourself to drive your asynchronous code. You can mix and match. And the big takeaway from this exploration is that the concepts were already there in Python 2. There's no new concept in Python 3, but there is new syntax. The syntax is nicer, so I do not want to dissuade you from going to Python 3. Please do use Python 3 if it's possible. And also, async is single threaded. And it's much simpler than dealing with multithreads. But the trade-off is that your entire code must be non-blocking. It must be asynchronous. You can't have code that's a little bit synchronous, and mostly asynchronous. It simply would not work, because some line will block. To study further, I do not recommend reading the documentation. It's the simplest examples tend to use sockets. And I don't know sockets. I didn't have time to go learn sockets. So instead, I recommend watching David Beasley's talks on YouTube. He has a handful of talks about async. You probably know him from being an author of the Python cookbook, very nice, hilarious talks, and very informative. And all his talks are actually quite worth watching. And it also included a very nice blog post where they really helped me to get started how the heck does it all work. Thanks for your attention. I teach at Hackbread Academy. It's a Python-based boot camp for women in San Francisco. And all the material is on GitHub. You can go and run it yourself. Thank you.