Visit our site to listen to past episodes, support the show, join our Discourse community, and sign up for our mailing list.
Summary
If you are trying to build a web application in Python that can scale to a high number of concurrent users, or you want to leverage the power of websockets, then Tornado just may be the library you need. In this episode we interview Ben Darnell about his work as the maintainer of the Tornado project and how it can be used in a number of ways to power your next high traffic site.
Brief Introduction
- Hello and welcome to Podcast.__init__, the podcast about Python and the people who make it great.
- Subscribe on iTunes, Stitcher, TuneIn or RSS
- Follow us on Twitter or Google+
- Give us feedback! Leave a review on iTunes, Tweet to us, send us an email or leave us a message on Google+
- We are also running a listener survey to get feedback about the show. You can find it at bit.do/podcastinit-survey.
- I would like to thank everyone who has donated to the show. Your contributions help us make the show sustainable. For details on how to support the show you can visit our site at pythonpodcast.com
- Linode is sponsoring us this week. Check them out at linode.com/podcastinit and get a $20 credit to try out their fast and reliable Linux virtual servers for your next project
- I would also like to thank Hired, a job marketplace for developers and designers, for sponsoring this episode of Podcast.__init__. Use the link hired.com/podcastinit to double your signing bonus to $4,000.
- Your hosts as usual are Tobias Macey and Chris Patti
- We recently launched a new Discourse forum for the show which you can find at discourse.pythonpodcast.com. Join us to discuss the show, the episodes, and ideas for future interviews.
- Today we are interviewing Ben Darnell about his work on Tornado
Interview with Ben Darnell
- Introductions
- How did you get introduced to Python? – Chris
- What is Tornado and what sets it apart from other HTTP servers? – Chris
- How did you get involved with Tornado? – Ben
- What was the inspiration for the name? – Tobias
- Tornado was created before the recent focus on asynchronous applications. What prompted that design choice and when might someone care about using async in their development? – Tobias
- What is involved in creating an event loop and what are some of the specific design decisions that you made when implementing one for Tornado? – Tobias
- How does Tornado’s event loop compare to other packages such as Twisted or the asyncio module in the standard library? – Tobias
- The web module appears to provide a minimal framework for developing web apps. How scalable are those capabilities and is there a recommended architecture for people using Tornado to develop web applications? – Tobias
- What are some use cases in which a developer might choose Tornado over other similar options? – Chris
- Could you please give our listeners an overview of Tornado’s concurrency options including coroutines? – Chris
- I see that Tornado supports interoperability with the WSGI protocol and one of the use cases mentioned is for running a Django application alongside a Tornado app. Is that a common way for providing websocket capabilities alongside an existing web app? – Tobias
- I noticed that Tornado provides non-blocking versions of bare sockets and TCP connections. Are there any add-on packages available to simplify the use of various network protocols along the lines of what Twisted includes? – Tobias
- Please tell us about the transition of Tornado to Python 3. What obstacles did you face and how did you overcome them? – Chris
- Based on your issue tracker it looks like http2 support is definitely on the roadmap. Could you please detail your future plans in this area? – Chris
- What are some of the common “gotcha’s” for people who are just starting to use Tornado? – Tobias
Picks
- Tobias
- Adventures of Riley
- Dayworld Trilogy by Philip José Farmer
- Chris
- Ben
Keep In Touch
Links
The intro and outro music is from Requiem for a Fish The Freak Fandango Orchestra / CC BY-SA
Hello, and welcome to podcast.init, the podcast about Python and the people who make it great. You can subscribe to our show on iTunes, Stitcher, TuneIn Radio, or add our RSS feed to your podcatcher of choice. You can also follow us on Twitter or Google plus, and please give us feedback. You can leave a review on iTunes to help other people find the show, send us a tweet, send us an email, leave us a message on Google plus We are also running a listener survey to get feedback about the show. You can find it at bit.do/podcastinit dash survey with a link in the show notes.
I would like to thank everyone who has donated to the show. Your contributions help us make the show sustainable. For details on how to support the show, you can visit our site at pythonpodcast.com. Linode is sponsoring us this week. Check them out at linode.com/podcastinit and get a $20 credit to try out their fast and reliable Linux virtual servers for your next project. And I would also like to thank Hired, a job marketplace for developers and designers, for sponsoring this episode of podcast.init. Use the link hired.com/podcastinit to double your signing bonus to $4, 000.
Your hosts as usual are Tobias Macy and Chris Patti. We recently launched a new discourse forum for the show, which you can find at discourse.pythonpodcast.com. Join us to discuss the show, the episodes, and ideas for future interviews. Today, we are interviewing Ben Darnell about his work on Tornado. Ben, could you please introduce yourself?
[00:01:39] Unknown:
Yep. Hi. My name is, Ben Darnell. I'm the maintainer of the Tornado library for Python. And, in my, in my day job, I'm the, cofounder of Cockroach Labs, where we're building a new, distributed database. It's open source in Go.
[00:01:53] Unknown:
I've heard about that. It's definitely 1 that's been pretty interesting and 1 that I'm keeping on my radar, so I didn't realize that you were working on that as well. Yep.
[00:02:04] Unknown:
So, Ben, how did you get introduced to Python?
[00:02:07] Unknown:
So I don't remember how exactly I first discovered Python, but it was it was very early in my, programming, programming education and I was trying to make the leap from, from basic and Pascal to c and was kind of, kind of struggling with it. And I learned about Python and, you know, tried it out and, really appreciated the fact that it was so, so introspectable that you could open up any object and look look in and see the, see the dictionary attribute on every object and kind of see how it, how it works that way. And then I, had some trouble building some c extension, and that gave me an occasion to go and dive into the Python interpreter source code and, extension library interface.
And that that was when a lot of things kind of fell into place for me about how developer tools, which I had thought were this kind of unimaginably complex software, could all be assembled out of out of, individually understandable components. And so that was, it's kind of a, a turning point in, in my understanding of programming and, part of the reasons that I reason that I've had a soft spot for Python ever since then.
[00:03:20] Unknown:
So, what is Tornado, and what sets it apart from other HTTP servers?
[00:03:25] Unknown:
So Tornado is a, is is several things. It's a web framework and a server and asynchronous networking stack that all all work together. And so the, using the using the entire stack together, you can make, asynchronous web applications which can very efficiently serve lots of, lots of connections to, to users that are just held open and able to serve, real time updates out to the web pages. So it was originally developed at FriendFeed, which was a social network that was acquired by Facebook in 2009, to power the, the real time updates on the web page for, for new posts and comments.
[00:04:06] Unknown:
And how did you get involved with Tornado?
[00:04:09] Unknown:
So I joined FriendFeed, actually, shortly before the acquisition by Facebook. And so I wasn't I wasn't around for the, the original writing of the, of the tornado code. I, I was there when when the decision was made to open source it, which happened shortly after the the Facebook acquisition. And so we went we basically went through the friend feed code base and found all of the, all of the things that looked generally useful and and pulled those out and made an open source library out of them. And then, maybe a year later in in 2010, I was at, at another startup called Grizzly, and we were using Tornado. And, the FriendFeed team at that time had moved on to other things, and so they weren't weren't doing anything with, with Tornado at the time. And so I picked it up and started making contributions back to it for what we needed for Brisley and ended up basically, really enjoying, that kind of open source work on the side and adopted the project and have been maintaining it ever since.
[00:05:08] Unknown:
So that extraction from an existing code base seems to be somewhat of a popular method for the progeny of various open source projects. So I'm curious if you can give a little more flavor of the overall process that was involved with that and some of the challenges that you had had to deal with in that process?
[00:05:29] Unknown:
Yeah. So, some parts of the system were able to, to be moved, more or less directly, like the, the the IO loop and a lot of the core code was able to, to translate pretty easily. Other things were, were more pick and choose which parts we wanted to include, like the the web module was kind of an incomplete copy of some things that, things that were used internally. 1 thing that, that I think we could have done better in the initial open sourcing of the project was in, potentially even doing it as multiple projects. Because what, what we realized in retrospect is that we had a bunch of things that were only loosely related. Things like the options module and the database module were not really connected to anything else in the framework and ended up not, not not being very cohesive with the rest of it. And so I think those might have been better off as a, as a separate, package and maybe also even splitting up some of the core stuff like splitting the, the web framework off from the lower level IO loop.
I think we ended up keeping it all as 1 big package largely because of the relative immaturity of the Python packaging ecosystem at the time. None of us knew anything about how to manage an open source package at the time and how to manage dependencies. Pip and PyPy were not as well established back then as they, as they've become since then, and so we've, I've certainly learned a lot about how to how to package things and would have, would have done that differently if I was starting over.
[00:07:10] Unknown:
And have you considered actually going back and separating out some of the different components of Tornado into their own packages now? Or would it just be, too much of a burden to people who are already using the project?
[00:07:23] Unknown:
So I have actually moved 1 module out. The, the tornado.database module is now at separate a separate package called torndb, and that would that was because it, it was not only weekly integrated with the rest of the, of the package, but it was, almost, almost a contradiction with some of the goals of the rest of the package because it was a, it was a synchronous, database layer, and it was just a very thin wrapper around my SQL DB. It didn't, it didn't support any other databases, and it only added a few things on top of, on top of my SQL. And so it was 1 of those things where we could either invest a ton of time into it and make it into a proper, database layer or that, you know, it's best to deemphasize it and let you, you know, let you use whatever other database layer you wanted. And so that was the that was the direction that we, that we chose. And so that that part's been moved out into a separate separate module. Everything else is still, is still in 1 in 1 package, and I think it's it doesn't really make sense to try and, try and split it up any any further at this point given the backwards compatibility concerns. Mhmm. And what was the inspiration for the name?
The name, that was just that just came out of a short, brainstorming session when we decided to open source it. It was 1 of the 1 of the things that, was, emphasized originally in the open sourcing of Tornado was its speed relative to other, to other, Python, web frameworks. And so we, so we wanted a name that that implied speed. There's also a little bit of a of a poke at twisted Mhmm. Which is, of course, the, the the other, big, big, asynchronous framework, which predated tornado. But it was mainly, we just, we we just threw a bunch of names out there, did some googling to see what was, what was available, and, tornado was the 1 that stuck.
[00:09:18] Unknown:
And you mentioned the twisted library as another asynchronous networking stack. And, I know that Tornado was created before some of the recent hype on asynchronous applications, particularly, after Node. Js at the scene. So I'm curious what prompted the design choice of using non blocking and asynchronous IO, and and when might someone care about using async in their development?
[00:09:40] Unknown:
So, asynchronous programming at on the server side, really came out of, really came out of 2 things. 1 is that, because of the GIL, Python doesn't have very good support for multithreading. And so you end up running lots of, lots of processes on a multi core server in order to make use of of all of those cores. And so the synchronization primitives that you get with, with the threading module and other, thread based libraries don't really apply in in a multiprocess world as well. And so if you run multiple processes, each of which having multiple threads, then you end up having to manage this kind of 2 layers of synchronization complexity.
And so if you run a single threaded event loop in each, in each of your processes, then you can, then you can simplify because then you don't need to worry about any sort of shared memory concurrency issues that come up with threads because you're, because you only have 1, 1 thread at a time per address space. And then, so that that that really simplifies the implementation and the and the concurrency concerns. And then, compared to just running a bunch of threads and processes, asynchronous systems are much more efficient at handling these, these tasks that are sort of at rest. So when a when a user has a connection to a web page and is waiting for updates, you you don't want that to be a very expensive object. And in a threaded system, threads tend to have a fairly significant amount of overhead.
And so, by making, by by using, asynchronous callbacks for for these idle connections, you're able to serve a lot more connections a lot more efficiently than, than you would with with threads.
[00:11:39] Unknown:
And I know that in some of the different asynchronous networking libraries, 1 of the issues that comes up occasionally is what's, lovingly referred to as callback hell. So I'm curious if, Tornado offers any syntax to help alleviate that pain.
[00:11:55] Unknown:
Yes. We do. Well, we don't offer the syntax. Python offers the syntax. But, we've, we we've supported coroutines ever since, ever since tornado 3.0 as, our preferred solution to avoiding, callback hell. And what this means is that you can have a, you can have a function that looks, more or less like a regular, regular function But, uses the yield keyword in older versions of Python or the await keyword in Python 3.5 to indicate a point where it gets suspended while it waits for something else to complete. And so each of these, each of these points where there's a, where there's a yield in your co routine is really it's it's essentially a kind of syntactic sugar for creating a callback, and then passing that back on to the event loop. And so you can, you can get all of the, all the benefits of, of callbacks in terms of their, relative efficiency and, explicit context switching, while still without having to completely turn your code inside out and and write, you know, have everything look, look kind of like it's going back to front when you have lots of nested, callbacks.
[00:13:10] Unknown:
So what is involved in creating an event loop? And what are some of the specific design decisions that you made when implementing 1 for tornado?
[00:13:18] Unknown:
So an event loop, at its core is wrapping around, some, some system provided by the, some service provided by the operating system to let you know when there is, activity on, on your network connections or potentially other things like, like pipes and timers and things like that. And so at at at its core, you're wrapping around, on UNIX, you're, you're talking about 1 of the system calls in, that Python exposes in the select module. There's select, poll, epol, and kq are the are the the ones the the major ones on the platforms that, that Tornado supports.
And, there's, there's some subtleties between, between these different, different libraries, but they're all pretty much the same. EPOL and KQ are the newest and fastest where they where they are available, And Tornado always uses, of the of these the various options that uses the best 1, the best 1 that it can find that it, that it supports. But all of these, all of these, system calls on the UNIX side have, have something, something in common, and that they're, that they're what's what's known as a readiness based event loop. This is where you have a, a callback that, or excuse me. You you have a system call that tells you of these, of these connections that I'm interested in, which ones would have new data if I tried to read from them right now. And so it turns out that, what 1 of the most fundamental design decisions you make in an IO loop, which we didn't even really realize was a decision when we made it, is whether you embrace that, that design where you have your, the event loop, which tells, tells higher level code that, that a connection is ready. And then you have that, that higher level code read from it, or whether the event loop does the reading and then just passes the data off to the, the higher level code. And this turns out to be a tremendously important decision because on Windows, Windows doesn't use a readiness based event loop. It uses, it uses a what's called a proactive instead of a reactive event loop. It, in, in Windows, the the operating system actually does the read and then comes back to you with the data. And, this, it turns out to be, very complicated to, to support both styles at once. In both, Twisted and asyncio, if you look at the event loop documentation, there are a lot of methods on there. There's, there's, listen TCP and connect TCP and listen UDP and send UDP fragment and all of these, all these things where the, the event loop has to know about lots of different things. It has to know about every different kind of connection that it may be asked to deal with.
Whereas on the Tornado side, the the event loop API is much smaller. You have basically, you know, listen for reads, listen for writes, and, and, cancel a previous listen. And that's because in the, readiness based abstraction, all the event loop really needs to know about is file descriptors, and it can treat these file descriptors as a black box. And so this, turns out to be why, Tornado doesn't have good support for Windows and probably never will, because we made this decision very early on that our API was going to be so close to the Unix, readiness based API that it would be a major change to ever switch over to something that could support both the Windows model and the Unix model. And, you know, this is something that, when I I realized that this is, that this was the consequence of the choice that we had made, you know, I kind of looked at that and, and thought about it for a long time, trying to figure out whether I wanted to try and make the changes that would be necessary to support Windows.
And then I realized that, that well, actually, the simplicity that you get from only supporting a single model, I actually really like that. And that's actually a big part of when I'm working with tornado, that's actually a big part of what I what what I like about the tornado event loop in comparison to the, the twisted and asyncio ones is the, is the simplicity of that interface. And so I've personally come to the conclusion that, you know, I'd rather have that, rather have that simplicity than the broader platform support, since, you you know, I I work on on Unix platforms and don't really anticipate a great, a great need for Windows support in my, in my personal development. And so that's kind of a a niche that Tornado has found itself fitting into that it's, relatively UNIX, UNIX specific in comparison to the other, asynchronous frameworks that are out there.
[00:18:02] Unknown:
And, extending this conversation a little bit, I'm just curious how the tornado event loop compares to those in other packages such as Twisted or the async IO module. I know you said that the API surface is a bit smaller. I'm just wondering if there are any other specifics that you can share.
[00:18:20] Unknown:
The, the differences in the APIs, the the amount of API surface area is definitely the big difference. I think that, all all all event loops are pretty similar under the under the covers. There's, there's really very little, very little practical difference between them, aside from the, the API, that that enables the, the Windows support. I think that, that the 1 feature that, that Tornado has that, I know asyncio doesn't, and I don't think twisted does is, the ability to use a, to use the signal dot setitimer, system call to set an alarm to, alert you if you're, if you have a blocking function that goes too long.
I found this really, really helpful in debugging, and I've been meaning to get, get a version of this added to, asyncio upstream, because that's that's the 1 thing that, that I really, find useful in the tornado event loop that I would miss if I switched over to the to the other, to to the asyncio event loop. Also on the subject of the differences between the 2 the 3 event loops. They're actually, so small that, within, tornado, there are implementations of 1 library's event loop on top of the other, on top of another. And so you can run, tornado on the twisted event loop or twisted on the tornado event loop or tornado on the, on the asyncio event loop.
And so they're all all these libraries are equivalent in terms of the, the amount of power that they expose.
[00:20:06] Unknown:
And do they have any significant differences in terms of performance? Or are they all pretty similar because they're relying on the underlying system calls?
[00:20:14] Unknown:
They're all pretty similar. It's ultimately just coming down to the, the underlying system calls. I haven't done a lot of direct performance comparisons across them, but I would be surprised if there were, if there were very large performance differences between the, between the different event loops. Now when when you're using the, the different, sort of cross event loop interfaces that I just mentioned where you're running 1 event loop on top of another, that, that layer of indirection does, does have a bit of a performance penalty. But, just running each each event loop in in isolation, I I think they're all pretty, pretty similar.
[00:20:56] Unknown:
And earlier you mentioned the web module, and it appears to provide a minimal framework for developing web apps. I'm curious how scalable those capabilities are and if there's a recommended architecture for people using Tornado to develop web applications or if it's more of a architected however you see fit kind of thing?
[00:21:14] Unknown:
Yeah. It's it's definitely, an architected however you see fit kind of thing, which is, which is both good and bad. It, you you know, if you're the if you're the do it yourself type, then, then you're probably going to enjoy that. If you're someone who likes a little more, a little more hand holding and kind of the opinionated structure that you get with a with a framework like Django, then that's, that then you probably won't, won't like Tornado as much. But what I've found is that for the, the applications that I've been, that I've worked on that use Tornado, we, get you know, each each projects project ends up extending the base, web framework in slightly different ways.
And so in that respect, I I find it, I find it very valuable to keep the, the core web module as, as reasonably small as possible and only add stuff to it when there's, that there's something that's clearly, common and reusable. And then you can keep the, keep the core small so that it's easier to extend in whatever direction a particular project needs.
[00:22:19] Unknown:
What are some use cases in which a developer might choose Tornado over other similar options? So,
[00:22:26] Unknown:
I think, depending on what you mean by other similar options, I think the biggest, the the biggest draw that, that brings people to tornado as far as use cases go is just anything involving a a real time website where you want to push, push updates out to the out to the user's browser, whether that's with WebSockets or long polling or server sent events. Any of these any of these features is going to be something that, where where you're you're going to want, an asynchronous component in your system to manage all of those all of those idle connections. But even even if you don't use that, Tornado is, 1 of the ways in which you can use the Tornado web framework is on, Google App Engine, which is a restricted environment where none of this asynchronous stuff works.
But you can still use the web web framework in isolation, and you're not getting the asynchronous features, but you still have that same, that same small core that I was talking about that you can then extend however you want. And so if you do if you are someone who prefers that kind of do it yourself development where you can, choose you organize the project however you, however you like, then this, maybe, maybe a framework that you would choose even without the asynchronous components.
[00:23:41] Unknown:
I see. So so as opposed to something like Django or even, you know, something like that where which imposes a fair bit of structure, if you take the concurrency out, Tornado is still a fairly compelling minimal skeletal framework to build on.
[00:23:59] Unknown:
Right. It's, it would be if you're not using the asynchronous features, then it would be kind of in the same category as Flask and other, other lightweight frameworks, as opposed to something, something heavier like and opinionated like Django.
[00:24:13] Unknown:
So speaking of concurrency, could you please give our listeners an overview of Tornado's concurrency options, including coroutines?
[00:24:21] Unknown:
Sure. So, broadly speaking, Tornado supports 2 different, 2 different styles of concurrency. The first and oldest is callbacks. This is, where you pass function objects around to, so so that you write that write lots of different functions. And whenever you do an asynchronous call, you pass a, a callback or, you know, or or a closure or continuation into that into that function so that, you can pick things up in a new callback with the results of your asynchronous computation. And that is, that that's kind of the classic way to, way to do this. This is, seen all over the place, especially nowadays in JavaScript, and it's really kind of painful to work with.
And so when, tornado was first developed, that's that's how it worked. And, you know, it was it it worked up to a point, but it was really irritating to take a to take a a function that was, run you know, 1 1 large function, and you needed to insert an asynchronous operation in the middle of it. And suddenly had you had to cut it up into into 2 functions and make sure that you passed all of your, all of your your variables between them and, make sure that everything was was being passed along in the in the right way. And you'd have to, create more complicated structures to do 2 things in parallel and then rejoin them later.
And it was, so so just generally irritating to work with. And then I saw a, I believe, I first saw this technique used in a in a package called monocle, where you could use the Python generators to, to implement coroutines. This idea was also, fleshed out by, David Beasley in several of his presentations that he gave at, PyCon. And so I I, started implementing a a coroutine framework for, for tornado. This is, what is today in the tornado dot gen module. And this, so so this, makes it possible to use coroutines, which are a special kind of function, which is asynchronous but looks like a normal function and that things are executed from top to bottom in in the normal way, and you can have, you you can have 4 loops and if statements and try catch and everything just, just works the way you, you would expect.
And so the this, this has become, really, I think, the the core focus of, of tornado and the the sort of the tornado style of doing things. Everything that I that I write these almost everything that I write these days in tornado is using coroutines and not explicitly passing callbacks around, because it really, it really helps organize the code in the way that you, in the way that you think about it and makes it much more, much more tractable to, to to do refactorings in the same way that you would any, any other way, while still, still preserving all the benefits of asynchronous, asynchronous code and keeping all of the, switch points explicit.
[00:27:32] Unknown:
And going back a bit to what you were saying about how Tornado is sort of similar in capabilities to Flask. I know that 1 of the common problems with dealing with an asynchronous framework is the database because sometimes the database libraries are blocking, and so it sort of defeats the purpose of having all of the asynchronous capability on top of that. So I'm wondering if there are any libraries that you're aware of or any that go along with tornado for handling that sort of, situation.
[00:28:04] Unknown:
So there there are. For example, there's, there's Momoco is a an asynchronous Postgres driver. There are several asynchronous Redis driver. There's a whole list of these. If you go to tornado web.org and click on links, that takes you to our wiki page where we track track a lot of these a lot of these libraries. But I want to go back to what you said about how asynchronous, synchronous access to the database defeats the purpose of an asynchronous framework. And I would actually, say that it it doesn't defeat the purpose. Remember when, Infiniti first developed Tornado, they were using a synchronous database driver.
And, and so they were still that they still got enough, enough value out of the asynchronous model to to to build the framework even though they were also using it with a with a synchronous database driver. And I think the, the trick is that when you have a database that's under your control and you can tune all of the queries, you know, if you have a query that's slow, then you're really going to ruin your performance if you do it in a synchronous database, database library on an asynchronous server because that's going to block the thread. But what you really want is for all of the queries that you're doing frequently to be very fast.
And if you're doing a, you know, if you're doing, a Memcache call, for example, Memcached is incredibly fast. And if you're on a local network, then you can, you can get a, get a response back from Memcache in, you know, in less than a millisecond. And when you think about how much, how much extra computation has to go on in the Python process for making a an asynchronous call because it has to go through, lots of function calls and unwind the stack and, go back to the event loop and make the event loop calls and then go back come back into your into your callback. That actually adds adds quite a bit of overhead. And so for example, for something as as fast as Memcache, you know, I would say that it's almost counterproductive to use a an asynchronous library with even with Tornado because it, because it has this has this extra overhead.
It's not entirely, it's not entirely counterproductive because you what you are gaining is you're greatly improving the worst case, behavior of the system. So now nowadays, now that we have coroutines and it's easier to use asynchronous, operations everywhere, I I would say go ahead and use the use the asynchronous drivers. But, originally, in the days of manual callbacks, I would actually say that in a lot of cases, you're you're better off just tuning your queries and making sure those go fast than paying the complexity cost of threading asynchronous callbacks throughout all of your code.
[00:30:55] Unknown:
The extra overhead isn't something I really considered, initially. So I can definitely see how for particularly instances where the, as you said, the response comes back very quickly, it would be counterproductive to use an asynchronous library. And so it would be more useful to use in cases where you are doing expensive queries or queries over a non local network. So for instance, if we're using a, you know, maybe a hosted Mongo instance or something like that. And you mentioned the Momoco driver for post grads. I'm curious if that's something that you could plug in for use alongside SQLAlchemy or if they would necessitate a type of RM?
[00:31:32] Unknown:
No. Unfortunately, because, asynchronousness is, it's kind of contagious. Anything that, anything that touches asynchronous code also needs to be asynchronous. And so SQLAlchemy is entirely synchronous, and so you you can't, you can't really do anything asynchronous with with SQLAlchemy. You would need a separate ORM. Yeah. You either need an entirely separate ORM designed from the ground up to be asynchronous, or there may be some, some way to kind of slice into SQLAlchemy at the right point to, to make make it asynchronous. I'm not sure what exactly that would, that would look like. I'm not familiar with the SQLAlchemy's internals.
Although, there is another technique you can use, which is, very clever. This was introduced by, Jesse Davis at MongoDB and his motor driver, which is an asynchronous driver for MongoDB, which uses greenlets to take the synchronous PyMongo driver and make it asynchronous. And so this is, this is a little bit, little bit magic. I'm gonna go go into a little bit, of technical detail here to explain how that, how that works. But with, greenlets, first, I should explain what, what greenlets are. They're a way of doing they're kind of a hybrid of threads and, and asynchronous programming.
The code that you write is still synchronous. There's no callbacks. There's no coroutines. But, instead of blocking a thread when you, when you wanna wait for network IO, it actually, the greenlet code kind of steps in and swaps out the stack, for, for another stack and then passes the, passes the network IO that you're going to do back to an event loop. And so it's a way of it's a way of getting, a lot of the performance characteristics of, of asynchronous programming and, and event loops while still, maintaining, a much higher level of compatibility with, with existing code, and you end up with something that still looks synchronous at the end of the day. And so this, turned out to be a way that you could plug a plug an asynchronous operation in the middle of the Pymongo driver, without having to spread that asynchronousness app throughout the, the entire code base. And, that has actually turned out to work, worked very well. I was I was, pleasantly surprised by that. I've been leery of greenlets in the past, because of vague compatibility concerns and and concerns about, blocking without realizing it or task switching without realizing it. But in this case, at least, it worked out worked out pretty well. And so maybe, maybe a similar technique could be used with, with SQLAlchemy.
[00:34:31] Unknown:
Yeah. That would be interesting to see how somebody would approach that. And if, so if anybody does do it, I would be happy to hear about it. So I see that Tornado supports interoperability with the WSGI protocol. And 1 of the use cases mentioned in the documentation is for running a Django application alongside a Tornado app. And I'm wondering if that's a common way for providing WebSocket capabilities alongside an existing app that was the predates Tornado or was written before the need for WebSockets was realized in the application context.
[00:35:01] Unknown:
Yeah. I think, you know, judging by the, judging by the number of Stack Overflow questions that that mentioned it, it does seem to be a pretty, pretty common technique or at least a a common desire. I think, unfortunately, it doesn't always work out very well because the it runs your Django application on the tornado IO loop and blocks the whole thing for the duration of your Django request processing processing or your Flask or, you know, whatever your WSGI framework is. And so, yeah, it effectively makes that you know, everything you do there is is synchronous, and it blocks the event loop. And so that can really really limit your concurrency. It's, you you can certainly do it. A lot of get you know, a lot of websites don't have extreme needs for concurrency and can get by with, with something like this, and it's also, useful as kind of a transitional strategy. This is the the 1 time that I've done this, Django and and Tornado in the same process, was at, at Bristly when we wanted to take our existing Django app and port it over to, Tornado completely and replace all of the, all of the Django Pits. And by running them in the same process, we were able to do this in kind of a a piecemeal fashion. But, the the, the the whiskey module actually has, I think is more interesting in the other direction where you wanna take an app that is primarily tornado and run, run a small WSGI app inside of that.
I've used this a few times in the past, for things like the dowser memory profiling library and the, tracing framework that's built into the App Engine SDK. Both of these, packages give you a little WSGI app that you can, you can run on your own server to give you access to your memory usage and, and performance information. And so I've used the the tornado wizgi adapter to embed these, these little wsgi apps inside my my tornado apps.
[00:36:59] Unknown:
So I noticed that Tornado provides non blocking versions of bare sockets and TCP connections. And I'm wondering if there are any add on packages available to simplify the use of various network protocols along the lines of what Twisted offers.
[00:37:12] Unknown:
Yeah. So we we don't include, any of these in Tornado itself, and we don't really intend to. I think it's, I think it's best for I'd rather have an ecosystem of different different packages all implementing different different protocols than to have everything sucked into 1, 1 1 giant package like like Twisted does with theirs. But, yeah, like I I mentioned earlier, you can go to tornado web.org. There's a a link there titled links, which takes you to a Wiki page that lists lists dozens of, of libraries implementing various, various protocols in, on top of the tornado stack.
[00:37:51] Unknown:
Yeah. I can definitely see the case for keeping the the core library smaller and letting people pull in exactly what they need rather than necessarily having all of the different protocols included by default and inflating the overall package size. Though I can also see the case for Twisted where having everything included would potentially make it easier for adding interoperability at points where you didn't necessarily know that you needed it and just being able to easily call out to a different portion. And also with having the external modules, there's the potential for more disparate API styles, whereas if it's all included in 1 library, it's generally going to be a little more unified.
[00:38:35] Unknown:
Yeah. Definitely. And especially, when you consider that, when Twisted was, was originally being developed. Again, the Python packaging ecosystem wasn't as mature as it is now. It was a lot harder to find and install and manage all of your, all of your packages. So I can I can definitely see why in, in the early days of Twisted, why they went with this kind of monolithic approach?
[00:38:57] Unknown:
I also think another advantage to breaking it up the way, Tornado has is that as just a for instance I mean, I think that that's 1 reason why twisted is still sort of languishing in the Python 2, not quite yet Python 3 category just because there's simply so much of it to port. And, Tornado being smaller and more concise probably had an easier job. This dovetails with the later question moving over to Python 3.
[00:39:24] Unknown:
Yeah. So, I mean, when you think about, Twisted and and Python 3 support, they're actually making very good progress on on that. The tricky thing is is just that because Twisted is is so large that, you know, when you know, they can't say that it's done because there are still lots of parts of of Twisted that are not running on Python 3, but large parts of it do. And so, you you know, when is it when is it going to be enough for your application? That's, you know, something that everyone kind of has to has to try, try for themselves and see, see what they, what they need. And so yeah. The fact that Tornado is you know, has a clearly defined, boundary about it, that has certainly, you know, helped clarify what's Python 3 and what's not.
[00:40:08] Unknown:
So speaking of the transition to Python 3, please tell us about the transition of Tornado to Python 3. What obstacles did you face, and how did you overcome them?
[00:40:18] Unknown:
Let's see. Well, the first obstacle I faced is that, Tornado had, very little in the way of unit tests or any kind of, any kind of test when, when I started, the move to Python 3. So because it's it's basically impossible to, to successfully port port to Python from Python 2 to Python 3 without, without a good test suite. That was the first thing I had to do was just get in there and and test, test everything. Even, even things that, you know, you wouldn't necessarily think about, think about testing normally, but, you know, you really have to make sure that you cover every, every code path so that you can see that you're, not mixing strings and bytes, inappropriately.
I think, but once I got that out of the way, the the next big hurdle was just that I think, Tornado falls into the category of software that is really among the most difficult to port to Python 3 in the sense that it has APIs that it exposes to the application developer that are mostly, mostly expressed in terms of, in terms of characters and Unicode strings. And but then it it deals on the wire with, with byte strings. And, and so, you you have to you have to deal with both kinds of data all over the place. And and, I found that, that the 2 to 3 tool, to do the automated refactoring from Python 2 to Python 3, wasn't a whole lot of help in doing this for tornado because the output of 2 to 3 is very heavily biased towards thinking that, anywhere you used a plain string in Python 2, you meant a Unicode string. And so it, it turns your plain strings, which were, which were byte strings in Python 2, it turns them into Unicode strings in, in Python 3. So So it took a lot of work to, to go through and annotate everything that I wanted to to treat as a as a byte string so that it would actually actually, stay, say a byte string after 2 to 3 got through with it. And, that this was this also, it turns out, because the the b string, syntax wasn't introduced until Python 2.6, the job of porting to of supporting, both Python 23 for tornado got a lot easier once we dropped support for Python 2.5 and were just, just 2.6 plus.
So we had some some growing pains just on on account of the the the amount of amount of history that we were trying to cover and how much, yeah, you know, which Python versions we were trying to support.
[00:42:54] Unknown:
I'm sure. Just out of curiosity, I know you mentioned that there were a number of things that you, you know, you really had to to up your game in terms of your your test suite. Can you think of if you can't, you know, obviously, it's no problem at all. But can you think of an example of a code path that you might have skipped over, but that turned out to be really useful to test in the transition to Python 3?
[00:43:17] Unknown:
The the thing that comes to mind when I think about something that I had to test that I wouldn't have necessarily thought about is, we have this HTTP request object, which has, maybe a dozen different fields on it. You know, there's a there's a headers dictionary. There's the URL, the path, cookies, things like that. And all of these things are strings. And, and so and we want those to be, you you know, just plain strings on either version of Python. So on that that means that on, on Python 3, these are going to be Unicode strings and not byte strings because, because Python 3 makes makes byte strings, a bit of a pain to work with. And on Python 2, we usually want those to be, to be byte strings rather than Unicode strings because, again, because introducing Unicode strings on Python 2 can, can be its own kind of headache. So we ended up having to, write a test case that that takes 1 of these HTTP request objects off the wire, and then it just does, like, an assert is instance on every 1 of those fields to make sure that it's that it's the right type of string.
[00:44:24] Unknown:
Gotcha. That makes that makes a lot of sense.
[00:44:27] Unknown:
And did you find that you had to do any sort of internal rearchitecting in in order to support Python 3 or to perform that transition?
[00:44:35] Unknown:
No. No. There there weren't any, any big structural changes. The the the big changes were just the fact that, like I said, having to go and mark up every string as either a byte string or a Unicode string. Yeah. So there there were small changes that were repeated in many places, and there were some functions that just needed to be, needed to be completely rewritten. There's there's a handful of things in in the Tornado code base where I just, throw out my hands and say, if sys.version is greater than 3, then, def, def food, this, this thing. And if not, do define it this other way. But, for the most part, once I sort of figured out, the right style for, working in the common subset of the 2 languages, it didn't require any, any changes that were individually large. It was just, just an accumulation of of tons of small changes everywhere.
[00:45:23] Unknown:
So based on your issue tracker, it looks like HTTP 2 support is definitely on the road map. Could you please tell your future plans in this area?
[00:45:31] Unknown:
Sure. So, as a case in point for our earlier discussion about, keeping the, core small and doing things in separate packages, The HTTP 2 server is actually being developed in a in a separate package, and, I've spent some time over the holidays working on it. And, just yesterday, I, kind of sent out the first, the first announcement that this is basically ready for people to, to, you know, start playing with and seeing how it how it works for them. So I think that, yeah, HTP 2 is, is very interesting for a framework like Tornado. I think that there are some, some features in the protocol that make it well suited for an asynchronous framework, like the fact that it's built around these, long lived multiplex connections.
And so, like, to implement h t p 2, you're already moving away from the, from the thread per connection that you might use in a naive h t p 1 server. And so in that respect, I think, Tornado is a is a good fit for HTTP 2. Also, at, at the application level, there are some interesting things that you can do like, like push promise, which is a way for the server to to push a file out to the client that the client hasn't asked for yet. And this can potentially, reduce a lot of the, the hoops that people jump through today to kind of, bundle up all their JavaScript and CSS files and sprite their images and things like that. It, it lets you push the push the data that the client needs out without waiting for the, the request to come in.
And this is something that, because Tornado is operating, across the full stack from the, from the network right up to the application, it's going to be easier for me to add, push promise support to Tornado than it would be for, say, WSGI servers and, and frameworks to support plumbing, all the necessary, push promise machine machinery, through the through the various layers of the stack.
[00:47:27] Unknown:
Yeah. I know that there's a bit of growing pain going on right now with people trying to figure out how to adapt or create a new WSGI protocol to support HTTP 2 since the current protocol is fully mired in the HTTP 1 spec and doesn't really support a lot of the capabilities that the new HTTP 2 protocol is adding in.
[00:47:51] Unknown:
Yeah. And then that's also related to the whole introduction of asyncio and, the Python 3.5 async and await keywords. These are things that you can't really use in WSGI effectively as the protocol stands today. But there it would be that that would be something that would be good to get into a a future version of the whiskey protocol.
[00:48:13] Unknown:
Yeah. Definitely. We've we've actually had other guests in our show talk about the difficulties inherent in retrofitting something like Wizgi, which I believe, Tobias, maybe maybe you have a better memory than I do. I could swear maybe it was the UWSGI folks or, you know, request response life cycle. And so it's gonna be quite a bit of work to get it up to HTTP 2 spec.
[00:48:49] Unknown:
H t p 2 doesn't really change things all that much. It's still, it's still fundamentally, request response. It, it it has basically the same semantics as, as HTTP 1. It's really just a few, a few things, that were introduced. Like the push promise, that's the only thing that really deviates from, from h t p 1. I think that the issues that I that I was thinking of for, for WSGI where you have, the inability to support things like, asyncio, that that's actually equally a problem for HTTP 1 and HTTP 2.
[00:49:27] Unknown:
Yeah. And also the difference between going from a string oriented to a byte oriented protocol between HTTP 1 and HTTP 2. So what are some of the common gotchas for people who are just starting to use Tornado?
[00:49:41] Unknown:
I think by far the biggest gotcha is, is just the mental week that it takes to understand blocking and non blocking interfaces and, you know, essentially, what it means to be asynchronous. Because I think that people hear about Tornado. They hear that it's, that it's efficient and fast and, good at serving lots of connections. And then the first thing they do is they write a they write a little test app that has a handler that has time dot sleep in it. And they're like, oh, this isn't, this isn't handling multiple connections at all the way I thought it would. That that's just something that, I don't know. I guess I guess we haven't done a great job of explaining.
It's a it's a it's a pretty big thing to to get your head around when you're first, first exposed to it. But, you know, just figuring out what what it means to be asynchronous and how to apply that throughout, throughout an application is is a pretty big hurdle, for people to, to get past.
[00:50:40] Unknown:
Yeah. And are there any utilities that you're aware of to help with debugging asynchronous code? Because I'm sure that that can contribute to some of the, confusion and difficulties of people just getting started.
[00:50:52] Unknown:
Not, aware of anything. I'm actually not much of a debugger user myself. I, I I tend to debug with, with print statements more often than not. And so, you know, that that works just fine in an asynchronous environment. It, yeah. But most, most debuggers do have, have some difficulties with with asynchronous code. Although, I think that the Python 3.5 async and await statements because it embeds a lot of the, a lot of the complexity in the language itself, I think a Python 3.5 aware debugger could be could be pretty good at, at working with, with coroutines.
[00:51:32] Unknown:
So before we move to the PICs, are there any questions that we didn't ask you think we should have or anything else that you wanna bring up? Well, just, on the subject of the async and await keywords, these are new,
[00:51:45] Unknown:
new statements that were introduced in Python 3.5 that make it that make it much nicer to write, write asynchronous asynchronous code. It, it essentially builds, builds coroutines directly into the language instead of being done in a decorator as we've done in Tornado. And because of that, it can actually improve performance by quite a bit. And so, I I think that, for anyone out there who's been on the fence about moving to Python 3, if you're interested in asynchronous programming, I I think that these, these new keywords are a big deal, and, and I think they're a good reason for, anyone who's been waiting to to to make the switch to Python 3. I think it's a good reason to and a good time to to come over and and give that a try.
[00:52:31] Unknown:
And are there any particular areas of the code base or any particular features or bugs that you would particularly like help with?
[00:52:40] Unknown:
So nothing that, nothing that stands out right now. I think that, you know, you can come, come to our GitHub page and, and look at the issue tracker and see, see if there's anything that that interests you. There are some, some modules there that I I just haven't ever really used personally. Like, I haven't worked on a tornado app that was internationalized. And so I I don't have any real practical experience with the locale module, for example. And so I think, get you know, someone who who has done that or has an interest in that area wants to, wants to get involved there, that could be a a good, good area to work in, or in whether whether you're, you know, actually getting in there and fixing things, or if you're just giving a feedback talking about here's the here are the parts that I use. Here's what works and what doesn't. That can be very valuable as well.
[00:53:33] Unknown:
You know, actually, that brings up a point. We originally, like, as you know, Ben, when we have an idea for an episode every week, we come up with a bunch of questions to ask, our guests. And 1 of the ones we had for you is what are some of the more interesting and novel applications for that you've seen for Tornado. And you expressed that might be difficult. You didn't really have a good answer for that. And that just sort of, speaks to what you just said, I think. I was talking to Tobias about it before the show. You know, there are all kinds of reasons why you might not be able to contribute back to open source. But I personally think that the least you can do, I cannot envision any conditions under which a simple email back to the project, you know, even if it's something as generic as I work in research or, you know, I work for the mad scientist whose lair is under a volcano and we're using this open source project for x, y or z. I can't envision even with the most stringent red tape where that wouldn't be permissible.
And I think it's important just to sort of give these people who are kind enough to donate their time and effort to building these things that we all use and love. Let them know. Give them give them some love. Let them know that their their tools are and and projects are being used. I think that's, you know, if we all wanna see open source continue to thrive, you know, we all read about burnout and the like, I think this is 1 important aspect of it. Just simply giving them the feedback and saying, hey. We're using your thing. It's cool. We love it. Here's what we're using it for to whatever level of detail you can you can give.
[00:55:14] Unknown:
Yeah. Yeah. I think, a lot of times, you know, what, what I see as the as the maintainer here is, you know, I hear from people that are having problems. People that have have questions running into bugs. I I don't always hear from people that are using it successfully. And so, yeah, you know, if if you fall into that, that category where you're kind of the, the the invisible, or a silent majority, or at least I hope it's a majority of people who are using, using Tornado successfully and, and happily, you know, yeah, it would definitely be, be great to hear, hear from people like that even if you don't have a, you know, a problem or a or a question to ask.
[00:55:51] Unknown:
So I guess with that, we will move on into the picks. So for my first pick today, I'm gonna choose a series of books called The Adventures of Riley. They're kids books. They're done in cooperation with the World Wildlife Foundation, and they're all stories about a young boy named Riley who has an Uncle Max who's a scientist and takes him on adventures all across the world to study different endangered species. So it's a great way to learn about some of the different animals that are on our planet, some of the challenges that they're facing, and also introduce kids to different areas of the planet. So I've been enjoying reading those with my kids.
My next pick is another set of books called the Day World trilogy by Philip Jose Farmer. They're a sci fi trilogy. They're set in the distant future where humanity, the population of the world, has increased to the point that we can no longer sustain everyone at the same time. And so people are broken up into days of the week that they are released from suspended animation to live their lives. And everyone during the other days of the week has suspended animation pods in the basement of these houses that they all share together. And the most heinous crime in this society is to be what they call a daybreaker, which is somebody who is awake all days of the week. And the main protagonist of the storyline is 1 such daybreaker.
So it's just a very interesting look at overpopulation and human rights and human freedoms and some of the challenges that we are potentially gonna face in the future. And it's a little prescient too because they were written, I believe, back in the 70s 80s before our population has increased to the scale that it's at right now. So definitely a fun read, definitely worth checking out. And with that, I will pass it on to you, Chris.
[00:57:53] Unknown:
Cool beans. Thanks, Tobias. My first pick is a series, a TV series by Netflix because they are on fire lately. It's called Sense8, and it is executive produced by J. Michael Straczynski. If there are any old science fiction fans in the audience, they will know that name. He is the dude behind Babylon 5, which is 1 of my favorite science fiction, television programs of all time. It's also directed by the Wachowski brothers of the Matrix fame. It's a really interesting kind of unusual storyline. The the the brief 1 some 1 sentence summary is people around the globe are having unusual sensations that they can't explain, and it just gets way more interesting from there. It's beautifully photographed. The acting is really good. It's got some really great, names and, you know, faces that you'll recognize from other places.
It's just great fun so far. My next pick is a book. I am usually not all that big on self help kinda books because I find them mostly to be very repetitive and a lot of kind of pandering. But this 1 has been an exception. It's called Habits of a Happy Brain, which is kind of a meh title because it sounds like getting to their self help y kind of thing. But what's kinda unique about this is this woman who wrote this, basically takes it from the perspective of this is how your brain evolved, and and the the evolutionary characteristics that it shares with all other mammals. These are the mechanisms that that it evolved for survival, in the sort of, you know, animal world.
And sometimes those mechanisms can come in really handy in our modern life. Oftentimes, they don't and but understanding how they work, like it's a very sort of neurochemical focused outlook on this stuff. Like, you know, if you encounter a situation that might be construed as as stressful, your brain releases cortisol which makes you feel crappy, like, you know, pensive, like there's something wrong. You know, in the animal world, that could be like, oh, all of a sudden you realize that a lion is stalking nearby. But in modern era, it could be something like, you know, you have a deadline approaching and so you get that you get that that release of that particular brain chemical, and so we all evolve coping behaviors that that may or may not be helpful like, you know, you might decide to go eat a snack, which you don't really need a snack. You're eating a snack because you're feeling stress, and maybe that's not the wisest thing to do.
The book sort of goes on from there and I just find this sort of functional approach to self behavior modification to be really fascinating. I don't know how effective it'll be with me but I'm I'm just I'm intrigued at the whole idea. And my last pick is, a cryptocurrency. It's a little unusual in the sense that it's not like Bitcoin. Bitcoin is basically almost strictly exclusively about sending and receiving value from person to person or address to address, I guess, more accurately. Ethereum is different. Ethereum is a a smart currency, in that, rather than simply having value that get like transactions basically, value going from person to person, it it allows for smart contracts, wherein as a for instance, you have a smart contract that encodes these particular gating factors that if the the, you know, certain things happen, then a certain amount of currency might get awarded to this person or that person.
The the language that this stuff is written in is a stack based language, not unlike 4th at the low level, but it has a number of programming interfaces, so you can program it in JavaScript and a number of other things. There's a Python implementation too. I'm just totally intrigued with this idea and and, it's being used for everything from sort of, you know, prediction marketplaces to, you know, blockchain based democracy efforts to all kinds of other things. It's just really totally fascinating to me. I haven't done anything with it yet, but I'm watching this space very closely because I think this could be a really big deal. And that's it for me. Ben, what kind of picks do you have for us? Alright. So my first pick is a podcast.
[01:02:32] Unknown:
I don't listen to a lot of, technical podcasts, but I really enjoy history and like, like a show that can tell a tell a story really well. And so my my pick is The Memory Palace, which is a podcast of, of little short, short stories from, generally from American history. The they're, like I said, they're they're really short. They're about 5 to 10 minutes each. It's a it's a good 1 to, to go back and, catch up on the archives if you like this kind of thing. But they're they're not like about big historical events. They'll, they're more about, kind of little little anecdotes like the, the first Ferris wheel in America, or something like that.
And, they're just really, really well told and, and so that's, that that's my, my first pick. Then my my next 1 is, is an application. So before before I was at FriendFeed, I I worked at Google, on Google Reader, and so my, my pick here is the app that I use as a replacement for Google Reader, now that that has been has been shut down and it's a news blur. This is a it's kind of a, as far as I know, it's a 1 man project, primarily, although it's it's open source. And so, so so anyone who's interested in it can, can contribute. It's, it's open source and and written in Python, but it's, you know, it's got the same, similar kind of, kind of interface and feature set that, that Google Reader had and, goes beyond it with some, some smart features for filtering your feeds, find things you like or hide things you don't like. And so I've been, I've been very happy with, with this, ever since, ever since, Reader went away. And, that's it.
[01:04:13] Unknown:
So I just wanna second The Memory Palace. It's a great podcast. Nate DeMeo, is the is the sort of host. And, you know, the stories, some of them are, like you said, just kind of really sort of quaint and and and really pleasant to listen to, and others will just pull at your heartstrings in the most incredible ways. Like, I don't know if you you heard the recent episode about the fire brigade during World War 2. Mhmm. That was just incredible. And and the great thing about this is that even if you are just sort of vaguely curious about history but don't necessarily have a lot of time or or don't have the sort of intestinal fortitude to sink yourself into a more in-depth podcast like like, Hardcore History, which I'm a huge fan of, this is ideal because each story is like, you know, 5 minutes or something in length. They're very short, very concise, and yet you really get a sense for the time and place. He has an incredible way of describing things that's just really worth listening to.
[01:05:18] Unknown:
Yep.
[01:05:19] Unknown:
Alright. So we wanna thank you very much for joining us this evening and, giving us some of your time to teach us about Tornado. Yeah. Thanks. It's been my pleasure. For anybody who wants to keep in touch with you or follow what you're up to, what would be the best way for them to do that? So the best best place to, keep up with, with Tornado is, is probably on on our mailing list. It's a Google group link too from, from tornado web dot org. Well, thank you again. We definitely enjoyed it. It's very interesting project and definitely 1 that I'm going to keep a close eye on, and I'm sure I'll probably end up using it pretty soon for my own work.
[01:05:55] Unknown:
Right. Thanks, thanks very much. It's been, been good talking to you.
[01:06:00] Unknown:
Thank you. Good
[01:06:06] Unknown:
night.
Introduction to Ben Darnell and Tornado
What is Tornado?
Ben's Involvement with Tornado
Asynchronous Programming and Tornado
Comparing Tornado with Other Event Loops
Concurrency Options in Tornado
Database Drivers and Asynchronous Programming
WSGI and Tornado
Transitioning Tornado to Python 3
Future Plans: HTTP/2 Support
Common Gotchas for New Tornado Users
Interesting and Novel Applications of Tornado