Skip to content
Melo Podcasts Home
CategoriesLanguagesFollowing

Episode notes

How many cores does your machine have, 10, 18? Your async Python code uses just one of them. That isn't a bug in asyncio. That's the design, and optimizing event loops to be faster by 20% doesn't change it. So Giovanni Barillari started over. Joe is the creator of Granian, the Rust-based server that powers Talk Python. His new project is TonIO, an async runtime written from scratch for free-threaded Python. Real threads, a handful of primitives instead of asyncio's pile of them, and it flat out refuses to start if the GIL is on.

Transcript

Read the transcript · about 11,730 words, follows along as you listen

Michael Kennedy:How many cores does your machine have? 10? 18? Well, your async Python code uses just one of them. That isn't a bug in asyncio. That's the design. And things like optimizing the event loops to be faster by maybe 20% with uv doesn't fundamentally change that. That's why Giovanni Bariliari started over. Joe is the creator of Granian, the Rust-based server that powers Talk Python and all the other things we run here. His new project is Tone.io, an async runtime written from scratch specifically for free-threaded Python.

Michael Kennedy:Real threads, a handful of primitives instead of async.io's pile of them, and it flat out refuses to even start if the GIL is present. This is Talk Python To Me, episode 561, recorded September 1st, 2026. Welcome to Talk Python To Me, the number one Python podcast for developers and data scientists. This is your host, Michael Kennedy. I'm a PSF fellow who's been coding for over 25 years. Let's connect on social media. You'll find me and Talk Python on Mastodon, BlueSky, and X.

Michael Kennedy:The social links are all in your show notes. You can find over 10 years of past episodes at talkpython.fm. And if you want to be part of the show, you can join our recording live streams. That's right. We live stream the raw uncut version of each episode on YouTube. Just visit talkpython.fm/youtube to see the schedule of upcoming events. Be sure to subscribe there and press the bell so you'll get notified anytime we're recording. This episode is sponsored by Sentry's Seer.

Michael Kennedy:If you're tired of debugging in the dark, give Seer a try. There are plenty of AI tools that help you write code, but Sentry's Seer is built to help you fix it when it breaks. Visit talkpython.fm/sentry and use the code Talk Python26, all one word, no spaces, for $100 in Sentry credits. And it's brought to you by us. Talk Python and Python Bytes both now have MCP servers. Point your AI at 10 plus years of Python episodes, transcripts, and show notes.

Michael Kennedy:Free. Click MCP in the nav at talkpython.fm and at Python Bytes. Hello, hello. Welcome back to Talk Python and me. Great to have you here, Joe. Hey, thanks for having me. It's nice to get back to the show. It's been a while. It has been a while. And we talked about Granian last time, the Rust-based web application server for Python. And I got to just take a moment and say thank you. We'll come back to this. But thanks for powering Talk Python and all the different things.

Michael Kennedy:I think across our web apps, I don't know, like 10 million requests a month. And it's been flawless. So thanks. I appreciate you serving up all the stuff for everyone.

Giovanni Barallari:Oh, yeah. Thanks. It's been a pleasure. Like, it's nice to see, you know, when something just works. like when you do something and like at the end of the day it just works and people start using it like of course like they they ask for a bunch of features you know um but it's nice to see yeah it

Michael Kennedy:is really nice to see and i think it's i think it's good now it's been a while since you've been on the show a couple years i don't i didn't check the exact date when i look back maybe people are new to the show or haven't heard your prior episode or just don't remember like give us a quick

Giovanni Barallari:introduction who you are yeah sure so i'm giovanni but everybody can call me joe i'm italian but i live in vienna i am working as a programmer in century but i'm a physicist so i think like that's pretty peculiar i've been like in the open source ecosystem uh mainly in python um probably for the last oh god I think like it's almost 20 years now um and fun fact like I actually started like um doing open source or or um contributing to open source projects even before actually working as a programmer so um yeah that's me I maintain like too many packages nowadays for like the energy I have.

Giovanni Barallari:But yeah, that's pretty much. Excellent.

Michael Kennedy:Yeah, I know how that goes with the packages. It's like, oh, here's a cool idea. I want to put it out there. If it gains no traction, you can shut it down. If it gains a ton of traction, you're excited. If it gains a little traction, but enough, then you got to keep working on it. That's kind of not ideal, right?

Giovanni Barallari:Yeah. And especially like nowadays with AI, like the amount of things you, oh, I have an idea. Like the chances like to just throw a bunch of agents into that and see what happens. It's very dangerous.

Michael Kennedy:I have an idea. It'll probably take me an hour. Let me see if I can validate it. Thursday afternoon, you're still like, oh, I'm still almost there. It's like, where did my week go? What happened? It's fun though, isn't it? It's a wild time.

Giovanni Barallari:Yeah, it's weird, right? Because in a way, we have this very powerful, not super constant tool. but it's very powerful and and sometimes just amazing like sometimes like what do you what you get back is just amazing and you say like oh okay that's nice that's unexpected sometimes is the dumbest thing possible you can you you can get but i guess like the point the main point is that i think it it shows up how as humans we have like a complicated relationship with tools it can exploit a bunch of weird human behavior sometimes so yeah yeah if you like building things

Michael Kennedy:you know create you've got ideas and you want to see them come to life it's an unprecedented time if if you really your main joy was to be in the code working on the little bits of nuance i can see that it's frustrating and uh there's there's a whole there's a whole thing that we go into there but that's probably not. But wow, what a crazy time, right? Yeah, absolutely. Yeah, so let's jump into the topics here. I think the first thing I want to do is let's just do a little dive into Granian.

Michael Kennedy:That's why I reached out to you to have you on the show the first time. Like I said, it's powering. I have on the Talk Python server, there's 33 different containers running a bunch of different things, and probably about 15 of them are running Granian. Nice. Yeah. So like I said, it's been really, really cool. just tell people what is Granian because I think not only is it interesting as a thing that you've done previously and been on the show before it's also an interesting lead-in to where we're going

Giovanni Barallari:with Tonio so what's great yeah sure uh so Granian is an application server for Python so in Python for historical reasons um we separated like the application layer from the HTTP layer so when we want to serve a web application in Python compared to other languages in which the server part is actually a part of the application. In Python, we tend to have a separated package, which is a server, and that server's import your actual application. And then we have application protocols to make the server talk with your application and back.

Giovanni Barallari:The two main protocols in Python are VUSGI or WSGI. I never really understood how to say that, which is like the original PET333, if I'm not mistaken. So it's quite ancient in the Python history. And once we had like AsyncIO, a new protocol emerged. That's called ASGI or ASGI because, of course, it's the asynchronous server gateway. So, Granian is, again, an application server, so you can consider it as an alternative to MicroVoosgi, Uvicorn, Hypercorn, and a bunch of other servers that happened during the years.

Giovanni Barallari:And, yeah, the peculiar fact is it's made with Rust. So, compared to all the other servers you might use in Python, all the HTTP part or the network layer is running completely out of the interpreter, which kind of alleviates the load on the interpreter, like on the Python side. And depending on the context, it might be more performant or it might stabilize your latency more.

Michael Kennedy:You know, I think thinking back now, I'm pretty sure that that was the reason I chose Granian. Not that it was a ton faster, but the P95 bad side of things. Like how much might it slow down under certain weird circumstances? It was way more stable than a lot of the other servers, right? And that's kind of what you're referring to.

Giovanni Barallari:Yeah, because again, like a normal server which runs everything into Python, Like it has this kind of side effects that when your application is starting becoming slow, it kind of becomes like an infinite loop in which like the server adds additional load to the interpreter, which is already like highly loaded from your application. And so like Graniac kind of avoids all of that because like even if your application is fully loaded, like all the web and network layer is out of the interpreter.

Giovanni Barallari:It doesn't disturb, let's say the interpreter with that.

Michael Kennedy:Yeah. I do want to just give a little bit of a hat tip to WSGI or WSGI. Because, yeah, you pointed out it is old, but it's really, really nice that if somebody is out there running on GUnicorn or they're running on some other server, MicroWSGI, which you should stop running MicroWSGI because it's not supported anymore. You don't have to change your code at all. You just take your flask or your Jenga or whatever, and you just say, now run here. And they just, Grandin talks WizGey or Asggy to that thing, and it's transparent.

Michael Kennedy:It's beautiful. Yeah.

Giovanni Barallari:I mean, there are like still some, you know, sometimes weird things like, like, Vertzoic has some subtleties, sometimes some nuances. So I had to like add some environment key just for Verzoic because under some circumstances, if that key is not there, things don't work exactly good. So yes, I agree that like having like the two protocols separated and coded like in a specific way gives you this ability to switch the server. On the other hand, sometimes, you know, you can be a pain in some time.

Giovanni Barallari:Yeah, for sure. But yeah, I'd say like we like recently it's getting more popular. So I'd say if I'm not mistaken, like a few weeks ago, I think I surpassed like HyperCorn in terms of downloads. Awesome. And yeah, it's used like in a bunch of different big companies, Microsoft, Google, for sure. We use it at Sentry, of course. And I think like Sentry is the only company in which we use like all the three supported protocols of Granian because Granian also supports like its own protocol, which is named like RSGI, I don't know, like RSGI, which is a redesign.

Giovanni Barallari:Risky. Yeah. um so yeah i'd say it's going pretty good um i think like the last let's say this year was mostly into um not not not not mostly about features i think features but mostly about you know making the thing more stable and covering like some edge cases um especially again we're using it the Sentry. So now like if something is wrong with Grinia, like I have people knocking on my door.

Michael Kennedy:I bet you do. Well, I mean, with Sentry, Sentry gets an insane amount of like an unimaginable amount of traffic. I'm sure with the error reporting side of things and probably a little more so these days on the MCP and API side as well with all the agents. I know that I use the MCP and absolutely love it. It's been incredible. It's really, really good. I could just say on my project hey there's a century error i got what's up like literally that's all i gotta say in clause like hold on we're on it and it's like yeah you know five minutes later it's like here's what's going on let's work on it you know yeah really good stuff uh i do want to give a quick shout out as well uh on this regard to gradient like people are like oh it's it's not as popular as server x or whatever right although i think that's starting to fade it's it's got 5 000 stars and a ton of people using it and so on yeah but it's also based on hyper from rust which itself has uh where where's my numbers, 410,000 projects using it. So it's really tested, right? And obviously the stuff at

Giovanni Barallari:Sentry as well. Yeah. Yeah. Like the only thing I'm sure about Granian is that like the HTTP stack, that's super safe. Like that's like, I could bet like everything I have on that. So if something is wrong in Granian, like that's on me, not on Hyper, like to be clear. This portion of Talk

Michael Kennedy:Python to me is brought to you by Sentry and Sear AI. There are plenty of AI tools that help you write code, but Sentry Sear is built to help you fix it when it breaks. The difference is context. Sear isn't just guessing based on syntax. It's analyzing your actual Sentry data, your stack traces, logs, and failure patterns. Because it has the full context, it can A, spot buggy code in review and help prevent issues before they happen, and B, identify the root cause of production errors.

Michael Kennedy:It can even draft a fix and hand the work off to an agent-like cursor to open a PR for you. Seer turns Sentry into a complete loop. You have your traces, errors, logs, and replays to see the problem, and now AI to help solve it. Join millions of devs at companies like Claude, Disney+, and even Talk Python, who use Sentry to move faster. Check them out at talkpython.fm/sentry and use code talkpython26, all one word, for $100 in Sentry credits. Thank you to Sentry for supporting Talk Python.

Michael Kennedy:I recently did a post over on my personal blog calling cutting Python web app memory by 31%. And I did a ton of analysis and stuff on how I was running Granian and different things, just how I was running Python. And I think this is going to be a good lead-in to where we're going as well. I got it to where I was using 1.3 gigs, let's say, for Talk Python training the courses specifically. And people are like, oh, it's just a little courses thing.

Michael Kennedy:Like, well, it has 178,000 lines of Python, so it's not a totally small project. But down by the end, I did a bunch of stuff on it. Lazy imports. I switched to async, which is why I brought this up. But somewhere down here, I don't know what the final number is. Here we go. In the end, I got it down to 450 megs from 0.28 gigs. One of the main reasons I did that as a way I want to kind of want to lead into like this, where we're going is I said, well, the way grading works is for each, either you can make multi-processes that are single threaded or it could do multiple threads and then it'll create a separate interpreter for each one.

Michael Kennedy:Either way, it kind of like replicates out the running. It'll create copies in one way or another of your code. And that, if you could run one of them, that would be great. But why do we have so many? We have so many because of the GIL. We have poor concurrency. It's really hard to handle a lot of load and like actually access, you know, my servers, eight cores. Like I could only access one core like normally, right? And so we do all these things to like explode them out.

Michael Kennedy:But what is the most expensive? Like five years ago, this was true on servers, but really is true now. What is most expensive? Memory, not compute, right? Yeah. Thanks AI. Thanks Altman. We really appreciate that. But we've free-threaded Python now. That's a thing. And so we're kind of moving into this world where we can take better advantage of the hardware and we don't have to multiply out. I know your process takes 500 megs of RAM, but we need four of them.

Michael Kennedy:So now you need two gigs just to run your code. We don't necessarily need that anymore. And grading would be a really good foundation for that. But let's just think broadly about free-threading and async as it is and stuff. I know you've thought a lot about this because of this project that you built. Well, what do you think?

Giovanni Barallari:First thing, can I say free threading to me? It's super exciting. And I don't know why people are not as much excited as me on this. Because this is, I'd say, the biggest thing that ever happened into Python since the beginning of Python. In the last 30 years. do you remember like Python 2 to Python 3 and all like, oh, now strings are not bytes anymore and everything is Unicode?

Michael Kennedy:Yeah.

Giovanni Barallari:That's nothing compared to, hey, the gil is not there anymore. Like we talk about like every Python room everywhere in the world, like at some point talked about the gil and why we have to do to have the gil, right? Right.

Michael Kennedy:The Gilectomy that Larry Hastings had, it seemed to perpetually be working on and never kind of went anywhere. Yeah. It took like 15 years of people talking about this and it finally landed.

Giovanni Barallari:Like last year, yes, of course, last year it was beta because like in Python 3.13, it was like, this is an experiment still. That was the asterisk on top. But since Python 3.14, that's considered stable. It's exactly as the normal GIL-included interpreter. And at the end of the day, the biggest part of all of this was using reference counting instead of singleton. So I guess I'm excited about free-threaded Python because finally I have the language I love the most.

Giovanni Barallari:not because of the structure, not because of types or how it's designed, but because of this awesome community that only Python language has, at least in my experience. And so finally, I can use this language with actual threads. So I'm not obliged anymore to think, oh, wait, we are in Python, so I need to use a C library or something to take advantage of my CPU, Especially given, I don't know, we are in the era of, hey, even if you buy a $200 CPU that probably has 12 cores or something.

Giovanni Barallari:So yeah, I'm very excited. I'm confused about the lack of adoption. I would love to see more adoption in this. And of course, like there are reasons, like every native C compiled extension has to be fixed to be thread safe. And probably like on a bunch of ancient extensions, that's not simple or easy. Yeah, I don't know, man. Like I'm just too excited. Like I want people to use free thread.

Michael Kennedy:I know.

Giovanni Barallari:And getting it is so much easier as well.

Michael Kennedy:it's just uv Python install, you know, that 3.14 T and you got it, right? Yeah.

Giovanni Barallari:And like, I don't know, I'm so pissed at the maintainer of the Docker images because we don't have like an official 3.14 free threaded image. Like why?

Michael Kennedy:Why? Oh yeah, that is actually a good point. Like it has been a year and a half and it just requires putting the T on the uv installed bit.

Giovanni Barallari:Yeah. Yeah, but again, to my perspective, free-threaded Python opens the window to do a bunch of... First, to solve a bunch of the issues you mentioned, which is, for example, in Centri, the number one issue is... I mean, Centri at the end of the day is this 18-years-old Django monolith. And so, yes, we deploy in several multiple different deployments, activating just some parts. But even so, like, yeah, we have the same problem, which is, hey, like, in order to use like one C view out of like a VM that GCP gives us, like, yeah, we need to spawn like four different processes and require like, I don't know, four, five, six gigabytes of memory for like a single pod.

Michael Kennedy:And not only do you have to do that, you also have to, anytime there's some sort of in-memory cache, like an LRU cache or something, every one of those has to be spun up for all four, not just for one, right? There's a lot of powerful sharing. Do we want to start talking about observability?

Giovanni Barallari:Because you cannot just use like the Prometheus SDK or anything like that. Because again, like then those became like four different instances. So you cannot even track like the same metrics unless you do like some weird tricks. Like, yeah, relying on the multiprocessing library. It's messy, man. So like, yeah, I think like FreeThreader like solves a bunch of problems, Especially in web development in Python. Because everybody says like, oh yeah, they did this just because of AI, you know, because they can like make things parallel, whatever.

Giovanni Barallari:I don't get that. Like, like we have like this amazing feature and it solves a bunch of problem on web development and also like it opens up the a bunch of new opportunities. Because again, like one of the most annoying parts in Granian, which is also Like one of the things that people opens like the most, the vast majority of issues about is because nobody understands like how socket sharing works across different processes. And again, like with FreeThreader, like that's just go away if we have something different from a Synco.

Giovanni Barallari:And I guess that's the, that's when we get on the point here. Because for example, like in Grainium, so Grainium supports FreeThreader Python scenes 2.0, if I'm not mistaken. And so when you use Granian on a free-threaded interpreter, workers become threads. They're no longer processes. And I can skip all the dance of, yeah, open the socket, but just bind on that, but not on listen, because then it gets to be shared across processes and so each worker can have his own backlog. It's a mess, man.

Giovanni Barallari:So on the free-threaded variant, Like, Grenian already, like, used threads. The subtlety is that each thread has its own event loop. So what Grenian cannot do today is sharing things between those threads. At the end of the day, yes, the application is shared, but, like, every request, like, if a repus comes to a worker, that's it. Like, there's no... You cannot cross boundaries, right? when you await for something, when you suspend for something, that's the loop, the event loop you're running into.

Michael Kennedy:Which is a big limitation for servers. Yeah, and one is calling await and another is calling await or maybe doing some work, but if they were the same event loop, one thing could run because the other is awaiting, but they're actually separate altogether, right?

Giovanni Barallari:Yeah, and also you can still end up in these weird conditions in which maybe, I don't know, 50% of your connection we're bound to a specific event loop. And so you also have like unbalancement between like the different threads. So you have like one thread that receives the vast majority of things, the other thread doing nothing. Yeah. Let's say like we have new opportunities. We kind of lack some libraries, like some libraries behavior that can actually give us like all the actual meat here.

Michael Kennedy:Agreed. I want to talk about one area before we dive in, the Tone.io, and that's just asyncio event loops. And I know during your presentation, so you gave a talk on this at EuroPython this year, and I'll link to the topic right here in the moment. But there are people like, oh, well, we have uvloops, so doesn't that kind of solve it? And I think that's a really interesting thought because without calling out anybody, I didn't intend to call out anybody.

Michael Kennedy:I think it just highlights in the Python space, There's just not a lot of thinking about what concurrency means, why it matters, how you program for it. And that's going to be a challenge. I think that's part of the challenge of what you're talking about with the adoption of free-threaded Python. But I think also it is a challenge in the sense that thinking about making the event loop faster by, I don't know, 20% or whatever uvloop actually does, which is great, it doesn't really address the fact that you're still only on one thread.

Michael Kennedy:Your event loop can access, like, I just, against probably better judgment, I just bought a Mac Studio Max, which has 18 cores. If I write one thread, that's about like 5% of the capacity of that machine. So what does it matter if it's 4.9% or 5.1% depending on which loop? I don't care. That is broken either way. I want 95% capacity. Yes. Right? And that's, I don't know. I thought it would be worthwhile to kind of like talk about uvloop a little bit.

Michael Kennedy:And you built our loop. And those things are great in their building blocks. Yeah. They're not the panacea. They're not the fix.

Giovanni Barallari:Yeah, and we also now have Marcelo Trzesitsky, the maintainer of UVCore and Starlet. It has recently published Zoovloop, which is another event loop for Python relying on libUV, but it's written in Zig. But yeah, as you said, all of these event loops, yes, they can optimize some of the hot part of the cycle. But basically, that's it. Nothing really changed the shape of how things work. And so, yes, for sure, you should actually install uvloop or r loop or zoo v loop or whatever to to speed up like because that's performance you're leaving on the table regardless right like so uh it's good to have this project because they also like can light uh some of the inefficiencies of a sink io in my opinion um so i think it's still good to have these projects and you should use them um but yeah they want like the best you can GAT is probably like in the order of like 20% in, and we're talking about like row throughput if you're just doing TCP and nothing else, which is nobody does like, like nothing does nothing out there.

Giovanni Barallari:Right? Like we do a bunch of stuff. Yeah.

Michael Kennedy:If you construct an example where basically all you're doing is waiting very efficiently, then you start to see those, those deviate. And also if you've got, like, I've got 10 tasks that run over two seconds. It does zero. It doesn't matter. This only matters when you're doing very, very fine-grained work and tons of it, and there's lots of switching and that sort of thing, right?

Giovanni Barallari:Yes, yes. And so, yes, I guess this was one of my realizations. Because, again, I worked on ArtLoop mainly last year. And working on ArtLoop made me realize two things. The first thing is that asimkayo, it's overcomplicated sometimes. It's so fun fact at the presentation I did about that loop in Python Italy 25. I had a slide asking to the audience, what's the difference between a protocol and a transport in Async.io. Because if you check the official documentation of Python and you get to that chapter, you will find out that they have like to try to explain you that difference.

Giovanni Barallari:they try to do that like in three different ways, which to my experience, like if you need three different ways to explain the same thing, something is deeply wrong.

Michael Kennedy:Definitely violates an Einstein core philosophy.

Giovanni Barallari:Yes. Also because like, again, if we think about the Zen of Python, like simple is better than complex, right? So that was my first realization, right? Because, again, like you have a bunch of primitives, like you have events, futures. Oh, by the way, every time they get spawned into the event loop, they get wrapped into a task. What is a task? Nobody knows. Oh, and by the way, when they actually run inside the event loop, they became handles. So we have a bunch of this weird thing that they're not really exposed to you if you just write async code.

Giovanni Barallari:But if you need to debug something when something is wrong, then you need all of that to understand what's going on, right? And the other realization, again, was, okay, I reached a point in which there's no other possible optimization in our book. Because the vast majority of CPU time spent here is around AsyncIO primitives. And I have one single thread. And so, like, the only, when I came to realize this, I just said, okay, wait a second. Is that, is really that hard to start like scratch whiteboard?

Giovanni Barallari:Like from the beginning, like let's just assume for a second, like asyncio never existed. And I want to do like async stuff in Python. What that look like? Like what, what does it mean to make like an asynchronous runtime in Python? Is that hard? And I don't know, like, I guess three or four weeks after this, I just got like an asynchronous runtime, a complete alternative asynchronous runtime running on Python with multiple threads.

Michael Kennedy:To be clear on free-threaded Python, right?

Giovanni Barallari:Yes, free-threaded Python only because again, to have like real threads I mean, the design is to have real threads, so the moment you have the gill, I say, no, no, no, runtime error, change your

Michael Kennedy:interpreter because this is not good, right? This portion of Talk Python I May is brought to you by our AI tools. You know that thing where you ask an AI something about Python and it confidently tells you about a library version from 18 months ago? Well, we fixed that, at least for our shows. Talk Python and Python Bytes both have MCP servers now. Connect Talk Python and your AI can search over 550 episodes, full transcripts, every guest in the entire course catalog. Connect Python Bytes and you get almost 500 episodes of Python news going back to 2026, including every link we've ever put in the show notes. That means you can say things like, ask Talk Python what astral joining OpenAI means for uv or what has Python bytes said about uv and get real answers with real links, not hallucination. Name the show in your prompt and your AI knows exactly where to look. And if you live in the terminal, Talk Python also has a CLI too. One line, uv tool install talk-python-cli and then search episodes, transcripts, guests, courses without ever opening a browser. It's open source and it outputs text, JSON, and Markdown,

Michael Kennedy:so it feeds the AI tools that don't speak MCP yet. And here's the real reason I built it. Both shows cover around 10 years of Python history. The people, the decisions, the packages that took over, and the ones that quietly didn't. This enhanced access is free. No account, no API key, nothing to buy. This history should belong to all of us. Visit talkpython.fm and Python Bytes and click the MCP link in the nav bar. Connect them right now to your agents so that they'll be accessible anytime you need them in the future. And so yeah, that was like kind of the landscape

Giovanni Barallari:in which I started building Tonio or Tonio. You can pronounce it like however you want. Like I'm

Michael Kennedy:Italian, so I say Tonio, of course. I think obviously, well, you have to do Tonio. So it's really good. But as it pairs to asyncio, tone IO also kind of like as a hat to that, right? Yeah.

Giovanni Barallari:But we have Trio. So that's not Trio.

Michael Kennedy:Trio is living there a little bit as well. Yeah. So this is a really interesting project that you have. And it basically says, what if we actually had threads? One of the things that's endlessly frustrated me about Python and asyncio and consequently I think the language implementation of async await is it's really good. I think, you know, the way it sort of turns async code into what looks like structurally serializable code or serial code is really, really nice.

Michael Kennedy:But the, the fact that the developer has to juggle loops and which loop and that loop. No, that's not the right loop. Like so many times I've been, Oh, I want to do this request. Oh, are you using court or an async web framework? You, there is an async loop, but not that one. you need the one created by the web framework. Like, oh, did you initialize the async database connection before it ran the web thing? And like, nope, that's the wrong one. And there's all this weird juggling that's just so janky.

Michael Kennedy:And I'm pretty sure it's janky because we didn't have true threads. And the possibility, oh, what if you crisscross this? Everything sort of falls apart. And if you could just say, look, it's just multi-threaded. And there is a thing that called the loop and that's where stuff runs. And I don't care who started it. It's our loop. When I need a loop, the runtime Python itself has a loop for me and I'll use it. Right. And I feel like you sort of took that philosophy a little bit.

Michael Kennedy:Right.

Giovanni Barallari:Yeah. I'd say like the number one inspiration for Sonio is Tokyo, which is the number one Rust asynchronous runtime. That's probably because like I spend like in Rust a bunch of time. So yeah, like, I don't know, for example, like the weird thing to me is like, we still like, if you just want to do like an asynchronous program in Python, like a program, like let's say a script or, I don't know, like a simple CLI, we still need to do like a synch.io run.

Giovanni Barallari:Like why? Like the, yeah, the amount of things you need to know and decide and stuff there is like completely different from other languages. Yeah. Because again, like think about JavaScript. You don't decide anything. Like that's async in JavaScript.

Michael Kennedy:That's true. Well, I'll tell you a little bit why you can't just, why you still got to call async run because there's like a foundational layer that's not present. And it's your job to write the foundation on which asyncio executes, right? Like it's still your job to figure, okay, how do I actually create a loop? How do I run a loop? How do I, like, it's your job. You can't just create an async def method and call it because there's nowhere for it to go until you go create, you know what I mean?

Michael Kennedy:There's like, there's just,

Giovanni Barallari:But the foundation isn't quite there. But again, it's an entry point, right? So in Tonio, for example, yes, you have Tonio run. You want to instruct everything and configure the runtime and do whatever you want. Yes, you can do that. You don't want to do that. You have a single decorator, which is Tonio main. You put it on your function, your entry point in your program, and it's done.

Michael Kennedy:Yeah. All right. Before we talk about that, before we get too much in the weeds of it, why don't you just give us like, talk us through writing a program in this. There's also two ways, like maybe you could, after you talk about this, you could like sort of get into the, what this concept of colored functions versus not, and sometimes call async code viral code. And like, let's just like talk through the differences here. Yeah. So, okay. Yes. Tonyo has two

Giovanni Barallari:supports two different syntax modes. And that's because, again, when I designed this, given that I just throw everything away and started from scratch, I ended up having a system which didn't really require async await syntax or a notation because at the end of the day, behind async await notation, those are generated, right? And so given the effort to support like two different syntax was like minimal, writing everything from scratch, I ended up like leaving up to the final user to decide, hey, you dislike async await temptation?

Giovanni Barallari:There's still plenty of people that like, I don't know why, but they argue like all the time about, oh, you know, like I have to put async everywhere and a wait everywhere, whatever. OK, you don't like that. Guess what? Tonya also have just a yield syntax. So instead of await, you just yield from the next coroutine you want to suspend for or wait for. And that's it. You don't need to write async def everywhere. To be here is still colored, right?

Giovanni Barallari:Because the moment you have a generator function, then whatever it calls it before has to be a generator. as well. But I guess my point was mainly like, okay, to support the syntax doesn't really take that much of a work. And once it was settled in, I mean, it's there and people can decide by, hey, you dislike one notation? Sure, just use the other one. But yes, let's say for people familiar with AsyncIO, the syntax, like the AsyncAwait syntax is very similar to AsyncIO.

Giovanni Barallari:So you basically have your coroutine, so your sync dev, whatever you want, and you await primitives or stuff. So the main difference is that instead of importing stuff from a sync.io, so like, I don't know, sleep or timer or whatever, you import similar primitives from Tonio. We, of course, have way less primitives because, again, like, as I said before, AsyncIO has too many primitives. And the only big difference from AsyncIO, let's say, native people is that you have, like, spawn methods.

Giovanni Barallari:So instead of saying... So in AsyncIO, when you want to make things, like spawn several tasks and then wait for all of them to complete, you usually do... You have different ways of doing this, right? You can have a task set. You can have scopes from Trio. But I mean, you can use gather so you can create tasks and then gather. with SyncIO. So Tonio is like, to do this is, you just have like two methods. You either spawn asynchronous stuff or you spawn something that is blocking and then the primitive is spawn blocking.

Giovanni Barallari:The other major difference from a SyncIO is that when you spawn something that gets run immediately. Whereas like in a SyncIO this is true only if you create a task. Otherwise, everything else is eager. So in order to run whatever you want to wait, you need to await. So in AsyncIO, the vast majority of operations bound together the launching the operation and waiting for the result. Unless you create a task that starts immediately and then you await later, right?

Giovanni Barallari:In Tonya, everything is wrapped around the spawn because you can call spawn and forget about it or you can await Tonya spawn to wait for the results, right? Or you can park the result of the spawn, the join, and join later. So that's, I don't know if, like, maybe it's more confusing than, it's hard to explain it simply.

Michael Kennedy:Maybe, but one of the challenges I've seen with standard asyncIO is you want to create a bunch of work and let it run, and then you want to get the answers back. So a naive way would be, like, call a bunch of stuff, and then when you call await, It's like you've got to create them not started and then start all of them and then go through each one and await them. Whereas this way, you get a list back and you just await them in order or await one after another somehow.

Michael Kennedy:They're already started, right? And so there's like the skip of this like, okay, I've got all the things that are going to become tasks, but I got to turn them into tasks so then I can await them because if I regularly await them, it'll still fall back to serial just running on the event loop, you know?

Giovanni Barallari:Yeah. And I mean, like in Tanya is the same. Like if you await a coroutine, it means like I want to wait that to happen, right? If you don't want to just spawn, park the result of spawn into a variable, await later. I think there's an example down below in the page about spawning something and awaiting later. Somewhere. There's a bunch of documentation. Spawning there, yeah. But yeah, the idea is, and again, I didn't invent anything because the syntax. Yes, this is the example. So in this example, we compute like numbers, like stupid example, but it is to give the point. So we start like two functions, which computes numbers. Then we await for third function. So we immediately wait for the third result. And then we wait for the first two results. So in the meantime, so when you do the first poem, those two functions start already, like immediately at that point in your code, which kind of makes sense if you think about it, because it's like syntax-based, like you're invoking those coroutines, right?

Giovanni Barallari:In that moment, you just don't await for them. And so at the end, like you just await for the parallel, actual parallel result. Like everything here is concurrent, but the only point in which you have parallel code, the actual parallel code is when you await for parallel, right? So that's the major difference from a Synco and Tonio. When you spawn stuff, that thing happened in parallel. So by default, Tonio starts with the number of threads equal to the number of your CPUs.

Giovanni Barallari:The blocking, Tonio also has a blocking pool for blocking stuff. But that's separate. Let's say the main work loop that runs your code, by default, you have X threads per CPU cores. So if you run this on your M3 Max, M3 Studio Max, what was it? You will end up having 18 threads running stuff. Yeah. Which is kind of what we want in general, right? Like if I write a program-

Michael Kennedy:I'm sure you can configure it, right? You could configure the thread pool to say, like, look, this thing has to be a good citizen. Let's just take the number of CPUs, divide by two or something like that so I can still do other work.

Giovanni Barallari:Yeah, you can like, again, that Tonyo main decorator or the Tonyo run method accepts some parameters so you can configure like the size of the standard thread pool, the maximum amount of blocking threads you want to spawn because that does get spawned on demand. you can configure if you want to have support for context bars because it's not that's another thing about python right like we kind of went from thread locals to context bars uh but in thonio that's a bit more complicated right because you have async code in multiple threads yeah because they used to leverage the thread right yeah so if you want to actually use context bars you have to tell to the runtime, right?

Giovanni Barallari:Because otherwise, like, some side effects might be weird in that condition.

Michael Kennedy:Hold on. Nomenclature definition, please, here. What are context vars for people who don't know? Give us examples. Oh, yeah.

Giovanni Barallari:So context vars, so the interpreter has these, every thread into the Python interpreter has what it's called a context. And so with a sync.io, so what was the problem? So we used to have thread locals, which meant like if I have two threads and I have, for example, a request, and I have to keep the request state global, like global between quotes in my code, but I want to use the correct request in the code and don't make them mix in the two different threads, states, we use thread vocals because that's basically like a dictionary, more or less, where you can store that data.

Giovanni Barallari:And that snapshot of data is for a single thread. Context var are a similar concept, but for a same code, which means you can store global, again, between quotes, global state from an asynchronous code, suspend, and when you get back, you have the correct object back instead of mixing global state between different coroutines. Was my explanation good?

Michael Kennedy:Yeah, that's good. People are probably pretty common with flask.request. Yeah. Because you've got a view method or maybe deep down inside some lower part of your program, you're like, well, I need to know what the URL was. You just say Flask.request, you don't pass it around. Like very handy, probably architecturally a bad choice. You know, it's hard to like test it out, right? And you mock it. I don't know.

Giovanni Barallari:Emmet does the same. It's the one thing I copied from Flask because I really like it. But I think we can do the same argument about database, right? Like with a synchronous database, like you have to start a context, Like, async with database, whatever, and then you need to pass that, like, all through. Like, a context bar is more handy. I don't know.

Michael Kennedy:Yeah, yeah. It certainly unlocks some really interesting things. Some extensions do cool things with it. So that's what you're talking about. But because it's not all just tied to the thread and using asyncio context variables, now it's kind of shared in potential ways. It's a little bit, you got to opt into it. That's right?

Giovanni Barallari:Yeah, CSR. Again, like, it's a Boolean when you want to start the runtime. And I mean, it's an implementation detail. So it is just to be like, I think the big warning at the beginning should have been like, Tonyo is very alpha right now. So maybe that decision will change in the future because I think right now the default is false. That might become true as soon as I stabilize the API. But yeah, the idea was if you're testing Tonyo right now, if you're using Tonyo to do some tests right now, I want the developer to explicitly state, okay, I'm going to use context bars.

Giovanni Barallari:Because again, the fact you have multiple threads and stuff happening in parallel, I just want for the developer to be sure if it's thinking model is correct before trying to do some stuff. Because again, Tony is multi-threaded. multi-threaders is usually like not it's it's i don't know i think for humans multi-threading is hard to get sometimes um so that's the trade-off right like uh yes we now have all of these capabilities on the other end we need to think about the fact that the sync io always had this uh hidden uh let's say a feature which is hey there's only one coroutine running at the time Whereas Antonio can have like whatever number.

Michael Kennedy:Yep. Now you still had to manage stuff across await calls. So that was, I feel like people felt like the GIL saved them from all thread considerations, like locks and semaphores and so on. And I don't think it did. There's not a guarantee that like a thread couldn't interrupt you. It's just less likely to interrupt you, right?

Giovanni Barallari:So like the simple thing is that it did around other primitives. So for example, in a SyncIO, it's really hard to deadlock yourself because you're using like a threading lock. Because again, like the hidden feature of a SyncIO is you have only one thread working on that shit, right?

Michael Kennedy:Yeah, exactly. Like you can do all the locks you want. It's the same thread in the re-entrance. Exactly. It's effectively a no-op other than it costs CPU.

Giovanni Barallari:Yes, exactly. Whereas in Tonio, like that's exactly where people usually make mistakes because now you have the Tonio locking because you have the asynchronous locks, but you also have thread locks, which are two different things. And if you, and so like you can deadlock Tonio. How? Yeah.

Michael Kennedy:Welcome to multi-threading.

Giovanni Barallari:Yes. Like you, you, you, you create, like you enter a threading lock and then you await a coroutine inside the threading lock. Now you're deadlocked. Yeah. Because the two things doesn't speak each other. But I guess my advice, if people want to start working in multi-threaded Python, my advice is just think about those two rules and then multi-threading is not that hard. Again, rule number one, never await inside a threading lock. That's a simple rule.

Giovanni Barallari:Also because in Python, you use width lock. So that's super easy even to identify, right? That's rule number one. Rule number two, you have multiple threads. So if you want to write into anything, I mean, all the objects are thread safe in free thread of Python because a dictionary is thread safe, a list is thread safe, whatever. But that doesn't mean like you can screw up in using those. Because if you write state anywhere, You might have like race conditions and side effects because you expect to write something and then expect to read that value.

Giovanni Barallari:But in the meantime, you have another thread right into the same location. So again, like my advice is rule number one, never use locks, threading locks, and then await. If you want to have an async lock, then use an async lock. So a Tonio lock for that. Rule number two, watch out. So you probably need locks when you want to be sure that, like, when you have a sequence of operation, right, on shared memory. Those are the two rules.

Michael Kennedy:I think with those two rules, multithreading is not that hard. Yeah, agreed. So does Tonio come with its own dedicated lock and synchronization primitives?

Giovanni Barallari:Yes, there's an entire sync module. So Tonio has different modules. Tonya time, which contains time primitives, like timeouts, timers, etc. It has async module, which contains all the synchronization primitives, so logs, semaphore, barriers, etc. It has the network module, which is one providing like sockets. So that's quite a big difference from a sync.io. So in a sync.io, we don't have like an async socket library. So if you think about the standard lib socket module, Tonio, AsyncIO needs you to use that and then pass the sockets to the event loop and then handle the socket through the event.

Giovanni Barallari:Whereas in Tonio, there's a network module and inside that module, there's a socket module, which has the same exact interface of the standard lib plus socket. The only difference is, of course, every async method is async in Tonio. there's the streams module inside the network module which is the high level trio like interface to make it easy to manage network. It has a file system module which contains all the standard open kind of

Michael Kennedy:methods that they async with open tonio.files.open something like that

Giovanni Barallari:yeah.fs yes and it also contains like mirror of the pathlib, standard lib pathlib, so you can use like frontoniofs import path and that path has all the methods that are required to be asynchronous so that's more or less like the design I don't think like so right now I'm at tonio 0.9.14 I guess and I don't think There's much left in terms of modules and primitives and features. The big feature missing is Windows support. More on that later. But yeah, I'd say I'm close to stabilize the API.

Giovanni Barallari:So right now, again, this is all alpha. That's mostly because there's only me working on this. And I have Fable working on a bunch of other things, which I guess like if I can digress for a second, I think like I have a very peculiar and unique way of using AI because right now I'm like, and I guess like it's a good use case to advertise. So the entirety of Tonio, so Tonio has maybe 1% AI written code. The only code that was written by Claude was the pytest plugin.

Giovanni Barallari:Oh, by the way, we also have a pytest plugin. so you can hide the smart tone. But that's the only part that I let AI touch. Everything else, like it's old school. I written all of it like the old way, text editor, not even any suggestion and everything. What I used AI for, and it helped me a lot into reaching a state in which I think Tonio is really stable now was to use AI to build projects that were using Tonio and stress test everything about Tonio.

Giovanni Barallari:So for example, I made a port of Pi, the harness from Maria Zeckner. So I made Claude rewrite the whole thing in Python because Pi is written in TypeScript, regardless of the name. So I made that entire harness with Claude saying, okay, take five, meter every behavior and just use Tonio to do everything. And that like helped me like catch like probably 95% of the bugs in Tonio. And I kind of started doing the same for the ecosystem. Maybe we can talk about it a bit later, but yeah, that's also like a super, it's super useful for me, right?

Giovanni Barallari:Like as a solo open source developer, which, yeah, I want to focus on Tonio. I don't have time to do all the other packages. And so, yeah, that was nice.

Michael Kennedy:That's a very interesting way. I hadn't really considered that. It's just like, I need users before I have users. I need these three use cases covered. So give me a web app that uses an async database. Give me this terminal app and so on. And that's, yeah, that's really cool. Yeah. Okay. I agree. Ecosystem is interesting. I want to talk about it. But before that, I want to come back to blocking threads. Yes. So blogging threads are CPU bound generally type of things.

Michael Kennedy:Is that right? So I think Tonio is a bit peculiar in this regard

Giovanni Barallari:because it really depends what your program does. Because if your program, whatever that is, has mixed load, which means like you have both IO bound stuff, like network, disk, terminal, whatever, and CPU bound stuff, then the only way to be sure that everything keeps running smoothly, like on the network part, the IO part, is to spawn the CPU bound stuff on the blocking thread pool. But if your program is just CPU bound, then who cares? Just use the normal thread pool because then you don't have anything to block.

Giovanni Barallari:like your CPU bound, your CPU limited. So the standard configuration of Tonio gives you exactly the perfect number of CPU cores to use. On the other hand, if you just have like IO bound. So again, like if you have just CPU bound work or just IO bound work, you can use like the standard pool, nothing particular like this. The blocking thread pool is useful only when you have mixed workloads and you need to balance them, right?

Michael Kennedy:Okay, how do I create such a thing? How do I start a task in one or the other?

Giovanni Barallari:So every await or yell destruction or a tonio spawn destruction runs on the standard thread pool. To spawn something on the blocking thread pool is just tonio spawn blocking. Done. You don't need to manage the size of the pool. You don't need to create the pool. If you want to control concurrency in the blocking threat pool, you either use, like, barriers when you spawn stuff or semaphores when you spawn stuff. But, yeah, like, in general, it's not different from spawning anything else.

Giovanni Barallari:Sure.

Michael Kennedy:So you can spawn blocking. Here's what I was thinking. Here's what I was getting at. That I think would be a sweet feature. You've got at tonio.main for the entry point, right? Yes. So that runs on tonio.run instead of just Python run or whatever. For functions that you know are computational, you would like to ensure that they run on a blocking thread or along those lines. You could put a decorator that just says tonio.cpu or whatever. I don't know.

Michael Kennedy:You come up with a name, but that way I don't even have to think. If I import another library also built on tonio, I don't know, oh, that function wants me to run it this way. No, I just call it. Antonio goes, ah, this is an async CPU one. So we'll scale it up, scaffold it up on that, basically.

Giovanni Barallari:That's a nice suggestion, okay? All right. I think it will land in Antonio 0.10, yes. Awesome, okay, cool.

Michael Kennedy:I like that. When you're in the function, the locality of the information that, oh, this is computational and so on is right there. But when you're calling, and especially in a big app, you don't know, right? So I think that would be really cool. So I'm glad you like it. No, we'll work on that. Awesome. All right, we got time for two really quick things. So one thing that is nice about standard asyncio is everyone uses asyncio if they're writing async code at the moment, unless they do something like Trio or one of these other things.

Michael Kennedy:So for example, if I use HTTPX2 or HTTPX and I, with async, you know, async with create a client of it and I await its get, that runs on the same sort of deal. but it's probably not compatible with Tonio, is it? And if it's not, what do I do?

Giovanni Barallari:Yeah, it's not. So I have one thing that is the current state, and I also have the idea for the future. So right now we have a package which is called TonioMonkey, and you probably can guess what it means, what it does. It basically like monkey patches popular, Or I would either say, like, asyncio native libraries I thought about in the last few months. That might be useful. And so I guess today we have, like, TonyaMonkey can monkey patch async. No, sorry.

Giovanni Barallari:PsychoPG. It can patch HTTPX and HTTPX2. It can patch Redis. And I think that's most of it for the moment. But I'm open for issues. If anyone from the listeners want to try Tonio to an existing code base and you have a package you would like to see monkey patched, just open an issue in the TonioMonkey repo or even in Tonio discussions, and I will look at it. Because again, right now I need the vast majority of possible use cases to see that I covered everything.

Giovanni Barallari:Ideally, as soon as I stabilize the API and I say, okay, this is the thing, my idea was to try to contact the NEIO maintainers to see if we can have NEIO backend in NEIO, which should be like a way easier way to deal with this. I'm not sure how much it's feasible because again, like the main problem for Tonio right now is that it doesn't support any of the synchio primitives. So if any code base like relies a ton on task or futures or whatever, that's not in the runtime.

Giovanni Barallari:Yeah.

Michael Kennedy:Okay. Interesting. But there are some choices. And are you also creating your own? I saw some custom HTTP or some other library or two.

Giovanni Barallari:I'm also trying to be a very contained ecosystem of libraries, mainly on the web part. So right now, I published a low-level HTTP library for Python that is compatible both with Asyncio and Tonio. It's called HTTPunk. I published an eye-level client, HTTP client, on top of that, which is called Punk Rec. So again, you can use that regardless of Tonio Asincaio, because the adaptation layer is inside the package. I kind of published a very beta experiment of a Uvicorn port to work in Tonio, Which I guess brings up a question like, hey, when will Granian support this?

Giovanni Barallari:Am I right? Yeah, right. So I have plans. It's actually way bigger plans for Granian. So as I said before, 2026 was a bit boring in Granian. Like, no, a bunch of new features, not a bunch of that stuff. But that's just because several months ago, I started designing two things for Granian. So the first is this revision two of the ArchGee protocol, which will be async independent. So it will become like a callback protocol because the other big feature I want to add in Granian is to support a bunch of runtimes.

Giovanni Barallari:So my idea is not the Granian tree, when it will land, no promises on the time here, but like when it will land, Ideally, it will support Asyncio, Trio, Tonio, gEvent, eventlet, and a bunch of stuff. So that's the idea, is to isolate, let's say, the protocol implementation and the Python runtime implementation. So it will happen one day. In the meantime, I wanted to have a test server to use with Tonio and see what happens. So that's why.

Michael Kennedy:Yeah, using something like Cord or FastAPI or something like that. If you were able to run it in Granian with the Tonio, Tonio backend, the async endpoints you write would be running on Tonio, yeah? Yeah, that's the plan.

Giovanni Barallari:In TonioMonkey, there are also patches for FastAPI, by the way. And I'm working on a one on Django. I need to ping Carleton on that because we met this year at this year, PyCon Italy, and we talk about it. So maybe in a month or so,

Michael Kennedy:we will also have like a patch for Django. Sweet. Yeah, I just had Carlton on to talk about basically all the async work in Django 6 and 6.0 and so on.

Giovanni Barallari:So that was fun. I watched the episode and I was like, huh, sounds familiar, huh, huh.

Michael Kennedy:Yeah, we've talked about that. I see. Interesting. All right. Well, I got one final main topic for us. Yep. Oh, yeah. What about windows? So. And I'm not putting pressure on you to do it. No, no, no. I'm just rounding out the conversation. Okay.

Giovanni Barallari:So if you ask me like a few months ago, my answer would probably be like that short video extract from a series like where you had the actor. Whatever. um you know i'm gonna not gonna not gonna swear on the podcast but uh uh you get what i mean uh so i i'm not so first of all like the usual problem so supporting windows in granian it's a pain man like a real pain like i'm not joking right because it has like all these quirk behaviors not just in python not just in terms of threads like do you know that win that that windows have as like a bug from i think it was like nt4 uh that like if you if you share a socket it becomes blocking and so you cannot use it like anywhere um so windows for start like windows is a pain and is a very weird operating system second i don't have like a windows environment because finally in 2026, I was able to finally have just macOS and Linux on all my machines, also for gaming.

Giovanni Barallari:So I'm so happy. So those are, like I say, the two main preambles on Windows support. But also because implementing the library I use Antonio to manage the Polar, the actual event loop, It supports Windows, but you know, weird way. So, months ago I was like almost a hundred percent convinced now, never windows, never now, thanks to fable by chatting with fable. I think we found a way to hack into, into meal, this library to, to fake some stuff about windows.

Giovanni Barallari:So it will interpret some stuff as TCP sockets. even if they are like file descriptors or anything. So I won't make a promise here because then I have to do it. But ideally, end of the year, we might see partial Windows support in Tom. Sweet. So that's the idea right now. I still hate Microsoft, to be clear here. Like, man, I just like Windows. So if any of the listeners, like if you're programming in Windows and not using Weasel, please put down in the comments why.

Giovanni Barallari:Like, why are you self-inflicting this to you? Like, explain me the rationale into dealing with all the BS that Windows 11 is nowadays. So yeah, but anyways, I will try end of the year to have some form of Windows support in time.

Michael Kennedy:I can tell, I can sense your excitement. My Windows computer over there is Windows 10, by the way. But I do think for people listening, Windows Subsystem for Linux is an escape hatch that you can do, right? If you had a project, you really want to use this here, like set up Windows Subsystem for Linux and run it there, right?

Giovanni Barallari:To be here, like the only reason I want to, like I want to try to add Windows support in Tonio is not for developers, is actually to provide developers a way to say, okay, I want to build a program in Python with Tonio that has to work like everywhere. Because right now, again, like if you code anything in Tonio, it works only on POSIX systems, so only Linux and macOS. So that's the reason why I want to have at least some form of Windows support because, I mean, it's not about developers.

Giovanni Barallari:It's about like where the software runs at the end of the day. Right, right.

Michael Kennedy:It's the deployment targets, yeah.

Giovanni Barallari:Yeah.

Michael Kennedy:All right, Joe, final call to action. People have been listening and they're like, this sounds pretty excellent. I want to try it. What do you tell them?

Giovanni Barallari:I mean, like, again, I think we're living in the perfect moment to try stuff. We've given with this big opportunity, big new opportunity of free-threaded Python. We have AI agents. And by the way, I was surprised, but like pointing any agent, any model, frontier model to a project and say, okay, implement this in Tonio. I was surprised. They got all the API correctly most of the times, which is amazing. There's no training data about Tonio. And regardless, it was able to drive through stuff.

Giovanni Barallari:So I guess it's the perfect moment to try stuff. I'd say if for any reason you're not happy with Asyncio, if for any reason you experience any of the pain points we talked about, I think it's like the perfect moment to try new stuff. And if you try Tonio and you have like a use case where it's not working or the API can be improved, like open an issue, open a discussion, ping me, DM me on Twitter. Oh, sorry, X the everything up. I will call it. Ping me and we'll figure out.

Giovanni Barallari:Yeah, I think that's my message.

Michael Kennedy:Yeah, awesome. Well, it looks like a very ambitious project and I think you've done a lot of interesting things. So thanks for coming on and sharing it. Tell people where they can stay in touch with you as well.

Giovanni Barallari:Yes, so my GitHub handle is G-I-0-B-A-R-O.

Michael Kennedy:You can find me with the same handle

Giovanni Barallari:Twitter. I have a blog, even if I don't write a ton, but you can find my blog at blog.baro.dev. And if you want to join me and Marcelo Trilesinski, again, author of Uvicorn, Starlet, and a bunch of stuff he's making with TokenMaxing, we recently started a podcast available on YouTube. at the www pod.

Michael Kennedy:Nice. So people, check them out. Check out the pod. That sounds fun. I'll give it a look as well. Joe, thanks for coming on the show. Nice to catch up with you. Thank you for having me. It was super good. This has been another episode of Talk Python To Me. Thank you to our sponsors. Be sure to check out what they're offering. It really helps support the show. This episode is sponsored by Sentry's Seer. If you're tired of debugging in the dark, give Seer a try.

Michael Kennedy:There are plenty of AI tools that help you write code, but Sentry's seer is built to help you fix it when it breaks. Visit talkpython.fm/sentry and use the code talkpython26, all one word, no spaces, for $100 in Sentry credits. And it's brought to you by us. Talk Python and Python Bytes both now have MCP servers. Point your AI at 10 plus years of Python episodes, transcripts, and show notes free. Click MCP in the nav at talkpython.fm and at Python Bytes.

Michael Kennedy:If you or your team needs to learn Python, We have over 270 hours of beginner and advanced courses on topics ranging from complete beginners to async code, Flask, Django, HTMX, and even LLMs. Best of all, there's no subscription in sight. Browse the catalog at talkpython.fm. And if you're not already subscribed to the show on your favorite podcast player, what are you waiting for? Just search for Python in your podcast player. We should be right at the top.

Michael Kennedy:If you enjoy that geeky rap song, you can download the full track. The link is actually in your podcast blur show notes. This is your host, Michael Kennedy. Thank you so much for listening. I really appreciate it. I'll see you next time. I'm me. Get me ready to roll. Upgrade the code. No fear of getting old. We tapped into that modern vibe over Kenny's storm. Продолжение следует...

Transcript supplied by the publisher with the episode.

Talk Python To Me

by Michael Kennedy · English · Tech & Science

Talk Python to Me is a weekly podcast hosted by developer and entrepreneur Michael Kennedy. We dive deep into the popular packages and software developers, data scientists, and incredible hobbyists doing amazing things with Python. If you're new to Python, you'll quickly learn the ins and outs…

More from Talk Python To Me

  1. E564 · 22 Sep 2026 · 1 hr 8 min

    #564: EVE Online Departs for Python 3

    Every ship in EVE Online eventually undocks and leaves the station. This time, it's the whole game. EVE has run on Python 2 since it launched in 2003, all 2.4 million lines of it, on a custom Stackless interpreter that stopped at 3.8 and was archived last year. Destination: Python 3.12. The route runs through 6,500 lines of division that decide who wins a fight, and 100 gigabytes of pickled Python objects that have to survive the jump intact. Kristinn Sigurbergsson was on this show ten years ago. He's back, with Jamie Bannister, who is flying the EVE Online migration right now, and Thomas…

  2. E563 · 16 Sep 2026 · 1 hr 11 min

    #563: Getting Started with Rust as Python Devs

    Lint the entire CPython code base from scratch. It takes 0.3 seconds. Three blinks of an eye. That is ruff, and it is written in Rust. So are Pydantic, Polars, uv, and Granian. Rust shows up in Python three ways: tools that happen to be Rust, libraries Python imports, and servers that run Python inside Rust. This is Rust for Python developers, not Rust experts. Christopher Trudeau is back on Talk Python to discuss Rust and his latest course Up and Running with Rust. The core rule is that only one thing can own a value at a time. Pass it around freely in Python and the garbage collector…

  3. E562 · 10 Sep 2026 · 1 hr 11 min

    #562: DuckLake: The Lakehouse That's Just SQL and Parquet

    How many files does your query read before it reads any data? On some data lakes, you go through JSON and metadata files first, just to learn which Parquet files matter. DuckLake asks one SQL question instead. The metadata lives in a real database. The data stays in plain Parquet. That's the entire format. Pedro Holanda joined DuckDB in 2018, when it was still a research prototype at CWI. He's the lead DuckLake developer. Guillermo Sanchez Dionis works on DuckLake and the new Quack protocol. With Quack as the catalog, DuckLake handles 200 transactions a second under heavy contention. No…

  4. E560 · 26 Aug 2026 · 1 hr 3 min

    #560: Building a Research OS: From Django to 30,000 Samples

    In 2020, a gastroenterologist in Glasgow did the math on his new research study and came up with 30,000 samples, arriving over two years from three cities and a dozen hospitals. He asked around about how researchers keep track of that. The answer was Microsoft Excel. Shaun Chuah had written some HTML by hand in Notepad back in high school and that was about the whole of his programming experience, so he opened the Django tutorial and started reading. Six years later that app is Foundry120, holding 10 terabytes of clinical and genomics data with an agentic AI running on top of it.

  5. E559 · 19 Aug 2026 · 1 hr 8 min

    #559: 12 Things You Should (and Shouldn't) Do in AWS

    Your site is down. It's 3am. Is it a bug, a bill, or a breach? You can't tell yet, and everyone is watching you find out. Matt Lea has spent fifteen years being the person companies call when an outage is costing them real money per hour, and his whole argument is that everything you'd want in that moment gets decided months earlier, on ordinary afternoons, when someone chose the convenient thing. We walk his top twelve dos and don'ts in AWS - infrastructure as code, IAM roles instead of access keys, private subnets, no wildcards, no public buckets - and I push on which of them actually…

  6. E558 · 10 Aug 2026 · 1 hr 2 min

    #558: Hyper-Personal Software with Python

    Every company has one. The little internal tool that Jane built back in 2021, and then Jane left. Nobody understands it, nobody will touch it. There are two unwritten rules around it: don't change it, it's working. And if you break it, you bought it. That's dark-matter enterprise software. For every app you can actually see, there are ten of these sitting in the shadows, frozen. Michael Booth thinks that just changed. He read my article on hyper-personal software and ran with it, writing about hyper-team software: small teams inside big companies finally building the tools that were never…

  7. E565 · 2 Oct 2026 · 1 hr 28 min

    #565: Tachyon, Python 3.15's Built-in Sampling Profiler

    Do you know what's actually slow in your Python app? Or are you guessing? Until now, profiling Python meant a tracing profiler that made your code 2 to 3 times slower. Or a third-party tool that broke with every new release. Python 3.15 fixes that. It ships Tachyon, a sampling profiler built into the standard library. It attaches to live production apps with almost zero overhead. My guests are Pablo Galindo Salgado, CPython core developer and Steering Council member, and László Kiss Kollár from Bloomberg's Python infrastructure team. Their first prototype ran at two samples a second. Now it…

  8. E557 · 2 Aug 2026 · 1 hr 8 min

    #557: Security of everything at PyCon 2026

    Security has always been the vegetables of software. Everyone agrees it matters, and somehow it never quite makes it onto the plate. At PyCon US this year, that changed. For the first time ever, security got its own dedicated, day-long track, one of just two at the whole conference, sitting right next to AI. And the room was packed to the back wall. On this episode, I'm joined by the three people at the center of it. Seth Larson, Security Developer in Residence at the Python Software Foundation and, very recently, a CPython core developer. Juanita Gomez, a PhD researcher at UC Santa Cruz in…

  9. E556 · 26 Jul 2026 · 1 hr 5 min

    #556: Updates on Django's Async Story

    For years, "Django and async" came with an asterisk. The docs themselves warned you off it. Scary performance notes, a story that felt half-finished. Well, that story just got rewritten, literally, and the person who rewrote it is here to tell you why the old framing was wrong. Carlton Gibson is a former Django Fellow, sat on the security team for eight years, and he's on the steering council. On this episode we get into the async topic doc rewrite, what actually remains versus what was just fear, the new Tasks framework in 6.0, DB-level cascades and fetch modes landing in 6.1, and why…

  10. E555 · 13 Jul 2026 · 1 hr 5 min

    #555: Marimo Pair - A Canvas for Agent + Developers Collaboration

    Coding agents have gotten really good at one kind of work. You scope a feature, edit some files, run the tests, ship it. It all happens on disk. But that is not how data work feels. You load something, you look at it, you run a cell, you watch how it responds, and you decide the next move from whatever is sitting in memory. And until now, your agent couldn't see any of that. It only saw the files. Never the live state. This episode, that wall comes down. marimo pair drops a coding agent right inside a running notebook, with full access to every variable Python is holding in memory. The…

Every episode of Talk Python To Me →

Take it with you

The Melo app keeps playing with the screen off, works in the car and on your watch, wakes you to your station, and browses the whole catalogue offline. Free, no ads, no account.

Get it on Google Play