There's been a bunch of renewed interest in making Python faster. While for some of us,
Python is already plenty fast, for others, such as those in data science, scientific computing,
and even large tech companies, making Python even a little faster would be a big deal.
This episode is the first of several that dive into some of the active efforts to increase the
speed of Python while maintaining compatibility with existing code and packages. And who better
to help kick this off than Guido van Rossum and Mark Shannon. They both joined us to share their
project to make Python faster. I'm sure you'll love hearing about what they're up to.
This is Talk Python to Me, episode 339, recorded November 1st, 2021.
Welcome to Talk Python to Me, a weekly podcast on Python. This is your host, Michael Kennedy.
Follow me on Twitter where I'm @mkennedy, and keep up with the show and listen to past
episodes at talkpython.fm. And follow the show on Twitter via at Talk Python. We've started streaming
most of our episodes live on YouTube. Subscribe to our YouTube channel over at talkpython.fm slash
YouTube to get notified about upcoming shows and be part of that episode. This episode is brought to
you by Shortcut and Linode, and the transcripts are sponsored by Assembly AI.
Mark Guido, welcome to Talk Python to Me. Fantastic to have you here. I'm so excited about all the
things that are happening around Python performance. I feel like there's just a bunch of new ideas
springing up and people working on it, and it's exciting times.
Definitely. You two are, of course, right at the center of it. But before we talk
about the performance work that you are all doing, as well as some of the other initiatives going along,
maybe in parallel there, let's just get started with a little bit of background on you. Guido,
you've been on the show before, creator of Python. You hardly need an introduction to most people out
there. But you have recently made a couple of big changes in your life. I thought I'd just ask you how
that's going. You retired, and we were all super happy for you on that. And then you said, you know
what, I kind of want to play with code some more. And now you're at Microsoft. What's the story there?
Oh, I just like the idea of retiring. So I try to see how many times in a lifetime I can retire.
And starting with my retirement from BDFL didn't stop me from staying super active in the community.
But when I retired from Dropbox a little over two years ago, I really thought that that was it,
that I believed it. And everybody else believed it too. Dropbox certainly believed it. They were very
sad to see me go. I was sad to go, but I thought there was time. And I had a few great months decompressing,
going on bike rides with my wife and family, fun stuff. And then the pandemic hit.
Yeah.
And a bunch of things got harder. Fortunately, the bike rides eventually got restored. But
other activities like eating out was a lot more stressful. Basically, just life was a lot more
stressful in general.
Right. And the human interaction was definitely shrunken down to a kernel.
Yeah. And somehow I thought, well, I want to have something to do. I want to do more sort of
software development in a team. And the Python core development team didn't really cut it for me,
because it's sort of diffuse and volunteer based. And sometimes you get stuck waiting for months for
the steering council to sort of approve of or reject a certain idea that you've worked on.
So I asked around and I found that Microsoft was super interested in hiring me. And that was now,
well, tomorrow, exactly a month, a year, tomorrow, a year ago, I started at Microsoft officially.
Yeah.
In the beginning, I just had to find my way around at Microsoft. Eventually, I figured I should pick a
project. And after looking around and realizing I couldn't really sort of turn the world of machine
learning upside down, I figured I'd stay closer to home and see if Microsoft was interested in funding
a team working on speeding up CPython. And I was actually inspired by Mark's proposals that were
going around at the time. So I convinced people, Microsoft to sort of start a small team and get Mark on board.
Yeah, that's fantastic. I also feel a little bit like machine learning is amazing, but I don't have a lot of
experience with it. And whenever I work with it, I always kind of feel on the outside of it. But this core
performance of Python, that helps everybody, right? Including even Microsoft, right? It maybe saves them
Oh, absolutely.
energy on Azure when they're running Python workloads or whatever. So you're enjoying your time? You're happy you're there?
I'm very happy.
Yeah, yeah, a lot of freedom to basically pursue what you are, right?
Yeah, it's nice that the new Microsoft is very open source friendly, at least in many cases, obviously,
not everywhere. But our department is very open source friendly. Things like Visual Studio Code are all open source. And so there was great support with management for sort of the way I said, I wanted to do this project, which is completely out in the open. Everything we do is sort of just merged into main as soon as we can.
Yeah, we work with the core developers. We don't have like a private fork of Python, where we do amazing stuff. And then we knock on the steering council door and say, Hey, we'd like to merge this.
Yeah, you're not going to drop six months of work just in one block, right? It's there for everyone to see.
Exactly.
I think that's really, really positive. And wow, what a change, not just for Microsoft, but so many companies to work that way compared to 10, 15 years ago.
Yeah, absolutely. Now, before I get to Mark, I just want to, you know, some bunch of people are excited that you're here. And Luis out in the audience said, Wow, it's Guido. I can't thank you enough for your amazing Python and all the community.
Great to hear.
Mark, how about you? How'd you get into this Python performance thing? I know you did some stuff with Hot Pie back in the day.
Yeah, that was sort of my PhD work. So I guess I kind of go into the performance almost before the Python. So I was doing sort of compiler work, masters. And obviously, just, you know, you need to write scripts and just get stuff done. And, you know, just Python is just a language to get stuff done. And then it's that, I think Armin Rigo, sort of, I think one of his sort of credits in one of his papers or something says,
Thank you for Python for being such a great language to use and such a challenge to optimize. So it's doubly good if you're coming at it from a sort of it. So it provides this great intellectual challenge when you're actually trying to optimize it. And it's a really nice language to use as well. So it's doubly good.
It is doubly good. It's doubly good. Yeah. And before we move on really quick, Paul Everett says, It's really impressive how the in the open work has been done. Yeah, totally agree.
Hi, Paul.
Yeah, keep that going. Hey, Paul, happy to see you here.
We're going to talk about making Python faster. But I want to start this conversation, a bit of a hypothetical question, but sort of set the stage and ask, how much does Python really need to be faster?
Because on one hand, sure, there's a lot more performance we can do if you're going to say, well, we're going to solve the in-body problem using C++ or C# versus Python. It's going to be faster with the native value types and whatnot.
On the other, people are building amazing software that runs really fast with Python already. We've got the C optimizations for things like NumPy and SQLAlchemy's transformation layer, serialization layer, and so on. So a lot of times that kind of brings it back to C performance. So how much do you think Python really needs to be optimized already? Not that more is always better, faster is always better. But I just kind of want to set the stage and get your two thoughts on that.
I always think back to my experience at Dropbox, where there was a large server called the Meta
Server, which did sort of all the server side work, like anything that hits www.dropbox.com
hits that server. And that server was initially a small prototype written in Python, the client was
actually also a small prototype written in Python. And to this day, both the server and the client
at Dropbox, as far as I know, and unless in the last two years, they totally ripped it apart,
but I don't think they did. They tweaked it, but it's still all now very large Python applications.
And so Dropbox really sort of feels the speed of Python in its budget, because they have thousands,
I don't know how many thousands of machines that all run this enormous Python application.
Right. And if it was four times faster, that's
not just for, you know, a quarter of the machines, that's less DevOps, less admin,
all sorts of stuff, right?
Oh, even if it was 4% faster, they would notice.
Yeah. The other area where I think it's really relevant has to do with the multi-core side of
things. I have a PC over there, 16 cores. My new laptop has 10 cores. Although with Python,
it's hard to take true advantage of that side of modern CPU performance if it's not IO bound,
right? Yeah. I don't know how deep you want me to go into that and Mark can stop me if I'm going too deep
too, but there are existing patterns that work reasonably well. If you have a server application
that handles multiple fairly independent requests. Like if you're building a multi-core web application,
you can use multi-processing or pre-forking or a variety of ways of running a Python interpreter on
each core that you have, each independently handling requests. And you can do that if you have 64 cores,
you run 64 Python processes.
Right. That's just a number in a microwave config file. It's nothing.
Yeah. It works for applications that are designed to sort of handle multiple independent requests in a scalable fashion.
There are other things that the other algorithms that you would want to execute where it's much more complicated to,
to sort of employ all your cores efficiently.
Yeah, absolutely.
That's still a nut that Python hasn't cracked. And I'm assuming you're asking this question because Sam Gross,
a very smart developer at Facebook, claims that he has cracked it.
Perhaps he has. It's an interesting idea. We'll dive into that a little bit later.
I'm more asking it just because I see a lot of people say that Python is too slow. And then I also see
a lot of people being very successful with it and it not being slow in practice or not being much slower
than other things. And so I'm more or less at the stage of like the context matters, right? This Dropbox example
you have, it really matters to them. You know, my course website where people take courses,
the response time of the pages is 40 milliseconds. If it was 38, it doesn't matter. It's really fast.
It's fine. So I think, but if I was trying to do computational biology in Python, we really want
to be able to take advantage of those 16 cores, right? So there's just such a variety of perspectives
where it matters. Mark, what are your thoughts on all this?
Well, it's just a case of saving energy, saving time. It just makes the whole thing nicer to use.
So, I mean, there's a lot of, you know, just iterative development in data science
and it's that responsiveness, the whole, you know, just breaking your train of thought
because things take too long versus just keeping in the flow and all that sort of stuff.
It's just nice to have something that's faster. I mean, it's not just the big companies saving
money as well. I mean, it's just, you know, just keeps everyone's server budgets down. I mean,
if you just need a smaller virtual instance, because you can serve the requests up fast enough
because Python's faster. So I think it's just generally a sort of responsible thing to do.
I mean, it's also just, you know, people expect technology to move forwards and there's this
feeling of, you know, falling behind or, you know, people wanting to move other languages because of
the perceived performance.
I do think that that's an issue. You know, I'm moving to go because it has better async support,
rewriting this in Rust for whatever reason. Sometimes that might make sense, but other times
I feel like that's just a shame and it could be used better. A couple of questions from the audience
just want to throw out there. Let's see. One was Guido, especially, you must be really proud to hear
about the Mars helicopter and the lander and Python in space. You know, how did you feel when you heard
about the helicopter using Python and the lander using Python and Flask and things like that?
It wasn't really a surprise given how popular Python is amongst scientists. So I didn't throw a
party, but it made me feel good. I mean, it's definitely sort of one of those accomplishments
for a piece of technology. If it's actually shot into space, you know, you've made a difference.
Yeah. I remember like 30 years ago or more when I helped some coding on European project called
Amoeba, which was like a little distributed operating system. And one of the things that
they always boasted was that our software runs on the European space station. And that was very important.
Yeah. So yeah, I totally get the feeling. And then I hope that everyone who contributed to Python
also sort of feels that their contribution has made it.
Yeah. And that sense of awe, if you look up in the night sky, it's that little,
that bright star that's actually Mars. And you think, yeah, it's up there. Yeah. Fantastic. All right.
Let's dive into some of the performance stuff that you all have been doing. So maybe Guido starts out
with the team. So you've, you've got a group of folks working together. It's not just you. And also now
Mark Shannon is working with you as well, right? That's correct. In March or so, the initial team
was Eric Snow, Mark and myself. And since I think since early October, we've got fourth team member,
Brent Booker, who is also a Python core dev since, I think since about a year and a half. He's a really
smart guy. So now we have four people, except you should really discount me as a team member because I
spend most of my time in meetings, either with a team or with other things going on at Microsoft in practice.
Sure. How closely do you work with, say, the VS Code Python plugin team and other parts? Or is this more
a focused effort?
This is more focused. I know those people. I've not met anyone in person, of course. I've not met,
I've not been to a Microsoft office since I started there, which is really crazy. But what we're doing
is really quite separate from other sort of Python related projects at Microsoft. But I sort of,
I do get called into meetings to give my opinion or sort of what I know about how the community is
feeling or how the core dev team is feeling about various things that are interesting to Microsoft or
sometimes things that management is concerned about.
Yeah. Excellent.
I'd be worth saying this, not just Microsoft as well. We've contributed from,
there's quite a few other core developers are helping out. So it's a broader effort.
This portion of Talk Python to Me is brought to you by Shortcut, formerly known as clubhouse.io. Happy
with your project management tool? Most tools are either too simple for a growing engineering team
to manage everything, or way too complex for anyone to want to use them without constant prodding.
Shortcut is different though, because it's worse. No, wait, no, I mean, it's better.
Shortcut is project management built specifically for software teams. It's fast, intuitive, flexible,
powerful, and many other nice positive adjectives. Key features include team-based workflows.
Individual teams can use default workflows or customize them to match the way they work.
Org-wide goals and roadmaps. The work in these workflows is automatically tied into larger company
goals. It takes one click to move from a roadmap to a team's work to individual updates and back.
Tight version control integration. Whether you use GitHub, GitLab, or Bitbucket, clubhouse ties
directly into them so you can update progress from the command line.
Keyboard-friendly interface. The rest of Shortcut is just as friendly as their power bar,
allowing you to do virtually anything without touching your mouse. Throw that thing in the trash.
Iteration planning. Set weekly priorities and let Shortcut run the schedule for you with
accompanying burndown charts and other reporting. Give it a try over at talkpython.fm/shortcut. Again,
that's talkpython.fm/shortcut. Choose shortcut because you shouldn't have to project manage your
project management. Mark, what's your role on the team?
I know we already have sort of official roles, but I guess I'm sort of doing a fair bit of
sort of technical, sort of architectural side of stuff, obviously, because this is like my field.
So right. Optimizer in chief. Yeah, I guess so. All right. Guido, you gave a talk at the Python
Language Summit in May this year, talking about faster Python, this team, some of the work that
you're doing. So I thought that might be a good place to start the conversation.
Yeah. Some of the content there is a little outdated, but...
Well, you just have to let me know when things have changed. So one of the questions you ask is,
can we make CPython specifically faster? And I think that's also worth pointing out, right? There's many
runtimes. Often they're called interpreters. I prefer to the runtime word because sometimes they compile and
they don't interpret. So...
Sometimes they're called virtual machines.
Yeah. There's many Python virtual machines, PyPy, CPython. Traditionally, there's been Jython and
Iron Python, although I don't know if they're doing anything. But your focus and your energy is about
how do we make the Python people get if they just go to their terminal and type Python, the main Python
faster? Because that's what people are using, right? For the most part.
I don't have specific numbers or sources, but I believe that like between 95 and 99% of people using
Python are using some version of CPython. Hopefully not too many of them are still using Python too.
Yeah. I would totally agree with that. And I would think it would trend more towards the 99 and less
towards the 95 for sure. Maybe a fork of CPython that they've done something weird too. But yeah,
I would say CPython. So you asked the question, can we speed up CPython? And Teddy out in the live
stream, I don't know if I'll be able to catch his comment exactly how there is. He says, you know,
what will we lose in making Python faster if anything? For example, what are the trade-offs?
So you point out, well, can we make it two times faster, 10 times faster, and then without breaking
anybody's code, right? Because I think we just went through a two to three type of thing that was way
more drawn out than I feel like it should have been. We don't want to reset that again, do we?
No. Well, obviously the numbers on this slide are just teasers.
Of course. I don't know how to do it. I think Mark has a plan, but that doesn't necessarily mean he knows
how to do it exactly either. The key thing is, and sort of to answer your audience question without
breaking on anybody's code. So we're really trying to sort of not have there be any downsides to adopting
this new version of Python, which is unusual because definitely if you use PyPy, which is,
I think, the only sort of competitor that competes on speed that is still alive, and in some use,
you pay in terms of how well does it work with extension modules. It doesn't work with all extension modules.
And with some extension modules, it works, but it's slower. There are various limitations. And that in particular
is something that has kept many similar attempts back.
If we just give this up, we can have X, Y, and Z, right? But that those turn out to be pretty big compromises.
Absolutely. And sometimes, I mean, quite often extension modules are the issue. Sometimes there are also
things where Python's runtime semantics are not fully specified. Like, it's not defined by the language
when exactly objects are finalized when they go out of scope. In practice, there's a lot of code around
there that in very subtle ways depends on CPython's finalization semantics based on reference counting.
And so anything, and this is also something that PyPy learned, and I think,
oh, Piston, which is definitely alive and open source. You should talk to the Piston guys if you
haven't already. But their first version, which they developed many years ago at Dropbox, suffered from
sort of imprecise finalization semantics. And they found with sort of early tests on the Dropbox server code
that there was too much behavior that didn't work right because objects weren't always finalized at the
same time or sometimes in the same order as they were in standard CPython.
Oh, interesting. So there's no promises about that, right? It just says, well, when you're done with it,
it goes away pretty much eventually. If it's a reference count, it might go away quickly. If it's a cycle,
it might go away slower.
That's correct. And unfortunately, this is one of those unspecified parts of the language where people
in practice all depend on, not everybody, obviously, but many large production code bases do end up
depending on that. Not sort of intentionally. It's not that a bunch of application architects got together
and said, we're going to depend on precise finalization based on reference counting. It's more that those
servers, like the 5 million lines of server code that Dropbox had when I left, were written by hundreds of
different engineers, some of whom wrote only one function or two lines of code, some of whom sort of maintained
several entire subsystems for years. But collectively, it's a very large number of people who don't
all have the same understanding of how Python works and which part is part of the sort of the promises
of the language and which is just sort of how the implementation happens to work. And some of those
are pretty obvious. I mean, sometimes there are functions where the documentation says,
well, you can use this, but it's not guaranteed that this function exists or that it always behaves the
same way. But the sort of the finalization behavior is pretty implicit.
Yeah, Mark, what are your thoughts here?
People just expectations is derived from what they use. The problem with documentation is like
instructions. They don't always get read. And also, it's not just finalization. It's also reclaiming
memory. So anything that has a different memory management system might just need more memory.
Reference counting is pretty good at reclaiming memory quickly and will run near the limit of what you
have available. Whereas a sort of more tracing garbage collector like PyPy doesn't always work so well like
that. I mean, one thing we are going to change is the performance characteristics. Now, that should
generally be a good thing, but there may be people who rely on more consistent performance.
You may end up unearthing race conditions, potentially that no one really knew was there. I mean,
but I would not blame you for making Python faster and people who write bad, poorly threads of code
fall into some trap there. But I guess that there's even those kinds of unintended consequences, I guess.
That one sounds like pretty low risk, to be honest. Yeah.
Yeah. Also, this sort of the warm up time, we'll get a warm up time. Now, what will happen is,
of course, it's just getting faster. So it's no slower to start with. But it still has the perception
that that now takes a while to get up to speed, whereas previously, it used to get up to speed very
quickly, because it didn't really get up to speed. It just started. It stays around. It stayed at the same
speeds. But these are subtle things, but they're detectable changes that people may notice.
Yeah. Also, like any optimizer, there are certain situations where the optimization doesn't really
work. It's not necessarily a pessimization, but somehow it's not any faster than previous versions.
Well, other similar code may run much faster. And so you have this strange effect that you make a small
tweak to your code, which you think should not affect performance at all. Or you're not aware that
suddenly you've made that part of your code 20% slower.
Yeah. It is one of our design goals not to have these surprising sort of performance edges. But
but yeah, there's a little cases where it might definitely make a difference. Things will get a
bit slower. Yeah. There are very subtle things that can have huge performance differences that
I think people who are newer to Python run into like, oh, I see you can do this comprehension. And I had
square brackets, but I saw they had parentheses. So that's the same thing, right? Well,
not so much, not so much. Not if it's a million lines of code or a million lines of data. All right.
So that's a great way to think about it. Not making it break a lot of code is I think as much as it's
exciting to think about completely reinventing it, it's super important that we just have a lot of
consistency now that we've kind of just moved beyond the Python two versus three type of thing.
I think also it's worth mentioning, Guido, you gave a shout out to Sam Gross's proposal. The stuff you're
doing is not Sam Gross's proposal. It's not about even from what I can see from the outside that much
about threading. It's more about how do I make just the fundamental stuff of Python go faster. Is that right?
That's right. These are like completely different developments. When we started this, we didn't
actually know Sam or that there was anyone who was working on something like that. But there had
been previous attempts to remove the gill, which is what Sam has done. And like the most recent one of
those was by Larry Hastings, who came up with the great name, the gillectomy. That's a fantastic name.
Yeah. He put a lot of time in it, but in the end he had to give up because the sort of the baseline
performance was just significantly slower than vanilla interpreter. And I believe it also didn't scale all
that well. Although I don't remember whether it sort of stopped scaling at five or 10 or 20 cores,
but right. Yeah.
Sam claims that he's sort of got the baseline performance, I think within 10% or so of vanilla
3.9, which is what he's worked off. Right.
And he also claims that he has a very scalable solution and he obviously put much more effort in it,
much more time in it than Larry ever had.
Yeah. And it sounds like Facebook
is putting some effort into funding his work on that, which is great.
Yeah. But it feels like a very sort of bottom up project. It feels like
Yeah.
Sam thought that that this was an interesting challenge and he sort of convinced himself that he could do it.
And he sort of gradually worked on all the different problems that he encountered on the way.
And he convinced his manager that this was a good use of his time. It's my theory, because that's usually how these projects go. But you almost never have management say, Oh, we got to fund an engineer to make faster or make a multi-core or whatever.
Find a good engineer.
Yeah. So you all are adopting what I see is going as the Shannon plan. As in Mark Shannon, the guests in the top left here. That's fantastic. I remember talking about this as well, that you had hosted this thing. When was this back? A little over a year ago. So interesting time in there, right? You had talked about making Python faster.
You had talked about Python faster over the next four releases by a factor of five, which is pretty awesome. And you have a concrete plan to sort of make changes along each yearly release to add a little bit of performance because the geometric growth may get quite a bit faster over time.
Yeah. Do you want me to run through these?
Yeah. Yeah. Tell us about your plan. You've got four stages and maybe we could talk through each stage and focus in on some of the tech there.
The way we're implementing is now kind of a bit of a jumble of stage one and two, but the basic idea is that, dynamic languages, the key performance improvement is always based on specialization. So obviously, you know, it's the most of the time the code does mostly the same thing as it did last time.
Yeah. And even in like non loopy code, you know, who are web server, there's still like a big loop level at sort of like requests response on a level. So you're still hitting the same sort of code. And those codes are doing much the same sort of thing. And the idea is that you, you transmit, you know, multiply the code. So it sort of works for those particular cases.
You should specialize it. So the obvious sort of simple stuff is, you know, like binary arithmetic. I have a special version of adding integers, special version floats. Obviously Python, it's much more to special versions for different calling, different things and different attributes and all this sort of stuff.
That's sort of the key first stage. I mean, that's mixed in with the second stage, which is really much more to just doing lots and lots of little bits and tweaks memory layout. So that's to do better, better memory layout. You know, modern CPUs are, you know, extremely efficient, but they still have to fetch from, you know, speed light issues with fetching stuff from memory. So, you know, how things are laid out in memory is key performance.
And it's sort of just those sort of little bits and tweaks here and just kind of writing the code as we would if it had been written for speed in the first place. So a lot of, you know, CPython is old and it's just sort of evolved. And a lot of it has, there's lots of potential for just sort of rearranging data structures and rearranging the code and so on. And these all add up, you know, a few percent here, a few percent there. And it doesn't take many of those to get a decent speed up.
So that's the sort of first two stages. And those are the ones where we have some pretty concrete idea what we're doing.
Right. And this is the kind of stuff that will benefit everybody, right? We all use numbers. We all do comparisons. We all do addition call functions and so on.
Yeah. I mean, the way we're sort of trending with performance in the moment is that sort of, you know, sort of webby type code, web backend sort of code.
You'd be looking at kind of where we are now, I don't know, it's a 25, 30% speed up.
Whereas if it's a machine learning, a sort of numerical code, it's more likely to be sort of 10% region.
Obviously we'd hope to push both up and by more, I don't think we're particularly focused on either.
It's just often the case where, you know, the next sort of obvious sort of convenient speed up lies.
And although everyone talks about speed ups and I've been doing the same myself, I mean, it's best to think of really at the time something takes to execute.
So it's often just shaving off 1% of the type rather than speed up by 1%.
And because, you know, obviously as the overall runtime shrinks, what were marginal improvements become more valuable, you know, shaving off 0.2% might be not worth it now.
But once you've sped something up by a factor of three or four, then that suddenly becomes, you know, a percent and it's worth the effort.
This portion of Talk Python To Me is sponsored by Linode.
Cut your cloud bills in half with Linode's Linux virtual machines.
Develop, deploy, and scale your modern applications faster and easier.
Whether you're developing a personal project or managing larger workloads, you deserve simple, affordable, and accessible cloud computing solutions.
Get started on Linode today with $100 in free credit for listeners of Talk Python.
You can find all the details over at talkpython.fm/Linode.
Linode has data centers around the world with the same simple and consistent pricing regardless of location.
Choose the data center that's nearest to you.
You also receive 24, 7, 365 human support with no tiers or handoffs regardless of your plan size.
Imagine that, real human support for everyone.
You can choose shared or dedicated compute instances, or you can use your $100 in credit on S3 compatible object storage, managed Kubernetes clusters, and more.
If it runs on Linux, it runs on Linode.
Visit talkpython.fm and click the create free account button to get started.
You can also find the link right in your podcast player show notes.
Thank you to Linode for supporting Talk Python.
Yeah, which leads on to stages three and four.
So, you know, just-in-time compilation is always hailed as the sort of the way to speed up interpreted languages.
Now, before you move on, let me just like sort of list out what you have on stage two for people who haven't dove into this.
Because I think some of the concrete details, you know, people hear this in the abstract.
They kind of want to know, like, okay, well, what actually are some of the things you all are considering?
So, improved performance for integers less than one machine word.
It's been a long time since I've done C++.
Is a word two bytes?
How big is a word?
Well, a word is how big depends on the machine.
So, that would be 64 bits for pretty much anything now.
Apart from like a little tiny embedded systems, which is 32 still.
So, that's a lot of numbers, right?
That's many of the numbers you work with are less than 2 billion or whatever that is.
Yeah.
I mean, basically, there are two types of integers.
There's big ones that are used for cryptography and other such things where, you know, it's a number in a sort of mathematical sense, but it's really sort of some elaborate code.
And then there's numbers that actually represent the number of things or the number of times you're going to do something.
And those are all relatively tiny and they'll all fit.
So, the long ones used for cryptography and so on are relatively rare and they're quite expensive.
So, it's the other ones we want to optimize for because when you see an integer, that's the integers you get.
You know, they aren't in the quadrillion range.
They're in the thousands.
Right, right.
Exactly.
A loop index or an array index or something.
Some languages, one that I'm thinking of that also maybe is kind of close to where Guido is right now, also in Microsoft space, is C#,
which treats integers sometimes as value types and sometimes as reference types.
So, that when you're doing like loops and other stuff, they operate more like C++ numbers and less like pi, you know, pointers to pi long objects.
Have you considered any of that kind of stuff?
Is that what you're thinking?
An obvious thing is an old thing as well is to have tagged integers.
So, basically, you know, where we would normally have a pointer, we've got a whole bunch of zeros at the end.
There's 64 bits.
A machine is three.
And then for alignment, there's effectively four zeros at the end.
So, we're using a sixteenth of the sort of the possible numbers that a pointer could hold, four pointers, which means leaves a bunch for integers and floating point numbers.
So, there's a number of what's called tagging schemes.
For example, LuaJit, which is a very fast implementation of Lua, uses what's called NAND boxing, which is everything's a floating point, but there is sufficiently something like two to the 53, which is a huge number of not a numbers in the floating point range.
So, you could use a lot of those for integers or pointers.
Now, that's a little problematic with 64-bit pointers because, obviously, 64 bits is bigger than 53.
But there are other schemes where you...
So, again, a simple scheme is that, basically, the least significant bit is one for pointers and zero for integers or vice versa.
And basically, it just gives you full machine performance for integers because you just basically, anything up to 63 bits fits in a 64-bit integer and has basically all of your numbers.
Interesting.
Okay.
Because it's shifted across all the machine arithmetic works as normal and overflows.
You just overflow checks a machine, a single machine instruction and things like this.
And that's, again, pretty standard.
And they need sort of like fast Lisp implementation and older small talk and other sort of historical languages.
JavaScript tends to use things like this NAND boxing I was talking about because all of the numbers are floating point numbers.
So, another one that stands out to me here is zero overhead exception handling.
Guido, that's making it into 3.11 already, right?
That's basically just what we used to have is we'd have a little setup and sort of tear down instruction for every time we wanted to sort of control the block of code inside a try.
As a try finally, but also with statements.
But we've just ditched those in favor of just a table lookup.
So, if there's an exception now, it's just looked up in a table, which is what the JVM Java virtual machine does.
Yeah, excellent.
Zero overhead is a slightly optimistic term.
It's obviously not zero overhead, but it is less.
You'll have a harder time finding it in the profiler.
There's a little bit of memory that you didn't have before.
That's a lookup table, but sort of it really is zero overhead if no exceptions happen, right?
Not quite.
Just because there is extra memories it causes.
But also, you know, because of like tracing guarantees, sometimes we have to insert a knob where the try was.
So, there's still some slight overhead.
And then potentially in future when we compile code, that should effectively become zero.
But it is definitely reduced.
Mark, Apple surprised the world and they took their phone chips and turned them into desktop chips.
And that seemed to actually work pretty well with their ARM stuff.
There's a switch not just having basically just x86 and 64-bit stuff to think about, but now you also have this ARM stuff.
Does that make life harder or easier?
Does it open up possibilities or is it another thing to deal with?
It's just harder because it's a bit harder.
And we may want to look to the future of RISC-V.
So, currently, CPython makes net is portable.
That's a key thing.
It's portability is, yeah, it rather depends on testing.
You know, it's all very well saying it's perfectly portable.
But if you have never tested on a platform, you may have surprises.
But it's all written in C.
And portability is a sort of serious consideration.
So, I mean, things like those tagging I was just talking about, that's technically not portable C.
But it's certainly, I mean, a lot of things aren't technically portable C, but in effect are.
I mean, technically, it's impossible to write a memory allocator in C because the specification says once you've called free, you can't access the memory, which makes it kind of difficult to write something that handles the memory.
But, you know, these are oddities.
But in practice, you know, if you write sensible C code, you should expect to be portable.
So, we are kind of basing around that.
I mean, like some other virtual machines, you know, particularly JavaScript ones are effectively written.
They're interpreted often written in Assembler or some variant of it.
There's definitely a performance advantage in that, but I'm not convinced it's great enough to lose the portability and the maintenance overhead.
Yeah.
And one of the things that you focused on, Guido, was that you wanted this to be, to keep, one of the constraints is you said you want to keep the code maintainable, right?
This is important.
Absolutely.
Why does that matter so much rather than if we can get 20% speed up if Mark refreshes his assembly language skills?
Well, it would leave most of the core development team behind.
And so, suddenly, Mark would be a very, very valuable contributor because he's the only one who understands that assembly code.
That's just how it goes.
Yeah.
And I don't think that that would be healthy for the Python ecosystem.
If the technology we used was so hard to understand and so hard to learn, making it so hard to maintain, then as an open source project, we'd lose velocity.
Right.
The only thing that would sort of cause to happen in the core team might be people decide to move more code to Python code because now the interpreter is faster anyway.
So they don't have to write so much in C code.
But then, of course, likely it's actually going to be slower, at least that particular bit of code.
That's an interesting intention to think about.
If you could make the interpreter dramatically faster, you could actually do more Python and less C.
I don't know.
It would have to be.
There's some big number where that happens, right?
It's not just a 10%, but maybe.
That could be in the distant future.
But nevertheless, I wouldn't want the C code to be unreadable for most of the core developers.
Yeah, I agree.
That makes a lot of sense.
Being a C expert is not a requirement for being a core developer.
In practice, quite a few of the core developers are really good C coders.
And we support each other in that.
We take pride in it and we help each other out.
I mean, code reviews are incredibly important.
And we will happily help newbies to sort of get up to speed with C.
If we had a considerable portion that was written in assembler.
Yeah.
And then it would have to be written in sort of multiple assemblers.
Or there would also have to be a C version for platforms where we don't have access to the assembler.
Nobody has bothered to write that assembler code yet.
All these things make things even more complicated than they already are.
Right.
And the portability and the approachability of it is certainly a huge benefit.
Two other constraints that you had here, maybe you could just elaborate on real quick, is don't break stable ABI compatibility and don't break limited API compatibility.
Yeah. So the ABI is the application binary interface.
And that guarantees that extension modules that use a limited set of C API functions don't have to be recompiled for each new Python version.
And so you can, in theory, you can have a wheel containing binary code.
And that binary code will still be platform specific, but it won't be Python version specific.
Yeah, that's very nice.
That sort of that we don't want to break that.
It is a terrible constraint because it means we can't move fields like the reference count or the type field around in the object.
Many other things as well.
But nevertheless, it is an important property because people depend on that.
Sure.
And the API compatibility, well, that's pretty clear.
You don't want people to have to rewrite code.
The limited API is sort of the compile time version of the stable ABI.
I think it's the same set of functions, except the stable ABI actually means that you don't have to recompile.
The limited API offers the same and I think a slightly larger set of API functions where if you do recompile, you're guaranteed to get the same behavior.
And again, there are sort of our API is pretty large and a few things have snuck into the limited API and the stable ABI that sort of are actually difficult to support with changes that we want to make.
And so sometimes this holds us back.
But at the same time, we don't want to break the promises that were made to the Python community about API compatibility.
We don't want to say, oh, sorry, folks, we made everything 20% faster.
But alas, you're going to have to use a new API and all your extensions.
Just recompiling isn't going to be good enough.
Some functions suddenly have three arguments instead of two or no longer exists.
Or return memory that you own instead of returning a borrowed reference.
And we don't want to do any of those things because that just would break the entire ecosystem in a way that would be as bad as the Python 3 transition.
Right.
And it's, yeah, just not just not worth it.
All right.
Let's go back to the Shannon plan.
So we talked about stage one and stage two.
And Mark, I see here this is Python 3.10 and Python 3.11.
Are those the numbers where they're actually going to make it in?
Or is it, do we have to do like a plus plus or plus equals on them?
I think a plus one would be appropriate.
All right.
Plus equals one.
Yeah.
So maybe we're a bit faster because obviously I envisioned this was basically me and one other developer.
Plus maybe sort of some sort of reasonable buy-in from the wider core development team.
So I wasn't sort of doing the work sort of entirely in isolation or, but yeah, I was still having extra hands will definitely help things.
Sure.
Yeah.
So back when you were thinking you were, this was written at 3.9 timeframe, right?
And you're like, okay, well the next version, maybe we can do this, the version after that.
And by the time it really got going, it's more like 3.11, 3.12 and so on, right?
Yeah.
It's just around the time.
I think we switched from 3.9 to 3.10 development.
I think I was sort of thinking.
Okay.
So stage three out of the four stages you have is, I guess, Python 3.13 now, which is a miniature JIT compiler.
Is that a right characterization?
I think that's not the compiler.
Well, I suppose it would be smaller.
Maybe the parts it applies to, the parts that get compiled.
Yeah.
So I think the idea is that you want to compile all of the code where it sort of forms as bad as it's sort of hot code.
But it makes life easier if you just compile little chunks of code and sort of stitch them together afterwards.
Because it's very easy to fall back into the interpreter and for the interpreter to jump into sort of compiled code.
And you can sort of just hang these bits of compiled code off by individual bytecodes where they sort of start from.
Obviously, that's not fantastic for performance because you're having to fall back into the interpreter,
which limits your ability to infer things about the state of things.
So obviously, if you've said earlier, a specialization, you have to do some type checks and other sort of checks.
If you've done a whole bunch of checks, if you then fall back into the interpreter, you have to throw away all that information.
If you compile a bigger region of code, which is of the stage four, then you already know something about the code and you can sort of apply those compilations.
The problem with trying to do big regions upfront is that if you choose poorly, you can make performance worse.
And this is a real issue for, well, the exact existing ones.
I think we're going to talk about some of the other historical sort of compilers in the past.
And this is a real issue for those that they're just trying to compile a method at a time, regardless of whether that is a sensible unit to compile.
Right. It's sometimes hard to do optimizations when it's too small, right?
Yeah. And also it's very expensive to do regions that are too big or just in the bounded in the wrong places.
Okay. Yeah. That definitely sounds tricky.
Guido, there was a question earlier about, you know, mypyC work and the mypy stuff.
And you are really central to that, right? Doing a lot of work there.
How do you, both of you, either of you, feel about using type annotations as some sort of guide to this compiler?
For example, Cython lets you say, you know, x colon int as a parameter, and it will take that as meaning something when you compile it with Cython.
It seems like, you know, Mark is talking about knowing the types and guessing them correctly matters in terms of what's fast here.
Is there any thought or appetite for using type annotations to mean more than static analysis?
It's a great idea. And I think for smaller code bases, something like mypyC will prove to be viable.
Or for code bases where there is an incredible motivation to make this happen.
I could see that happen at Instagram, for example.
But in general, most people haven't annotated their code completely and correctly.
And so if you were to switch to using something like mypyC,
you'd find that basically it wouldn't work.
A large number of cases.
And it would basically sort of, it's a different language, and it has different semantics, and it has sort of different rules.
And so you have to write to that.
I can see there's a big challenge to say, hey, everybody, we can do this great stuff if you type annotated.
And only 4% of people have properly annotated their code.
And then there's also the possibility that it's incorrectly annotated, in which case it probably makes it worse in some way of a crash or something.
mypyC will generally crash if a type is detected that doesn't match the annotation.
And if you annotate stuff with simple types, you can get quite good speedup.
So number is generally designed for numerical stuff.
But again, it's the simple types, integers, floats.
Cython, obviously, will do this.
Number does it dynamically, cython, statically.
And the number model, for example, is similar to the model that Julia language uses.
Essentially, you compile method at a time, but you make as many specializations as you need for the particular types.
And that can give very good performance for that sort of numerical code.
But the problem is that saying something is a particular type doesn't tell you very much about it.
It doesn't tell you what attributes an instance of it may or may not have.
It depends, you know, because you can, it's not like Java or C++ where having a particular class means it has those instance attributes and they will exist or at least there exist in a particular place and they can be checked very efficiently.
Because if dictionary lookup and so on, these things get a bit fuzzy.
72 bytes into this C object is where you find the name or something like that, right?
Yeah.
So because we basically, because anything might not be as the annotations say effectively at the virtual machine level, we have to check everything.
And if we're going to check it anyway, we may as well just check it once up ahead as we first do the compilation, whatever specialization, and then assume it's going to be like that.
Because if the annotations are correct, then that's just as efficient.
And if the annotations are wrong, we still get some performance benefit and it's robust as well.
So there's really no, the only advantage of the annotations is for this sort of like very sort of loopy code where we can do things like, you know, loop transformations and so on, because we can infer the types from the arguments of enough of the function to do that stuff.
And that works great for numerical stuff.
But for more general code is problematic.
What about slots?
Slots are an interesting, not frequently used aspect of Python types that seem to change how things are laid out a little bit.
Yeah.
Is that?
Well, mypyC actually, one of mypyC's main tricks is that it turns every class into a class with slots.
Okay.
If you know how slots work, you will immediately see the limitation because it means there are no dynamic attributes at all.
Yeah.
These are what you get for your fields and that's it.
Yeah.
I mean, if you don't have dynamic attributes, though, it gives you pretty efficient memory use.
I mean, it's a little too far up Java.
So it's...
And more predictability about what's there and what's not, which is why it came to mind.
Yeah.
I mean, they definitely have their use.
Yeah.
All right.
Mark, that was your four-stage plan, hoping to make 1.5 times as fast as before each time, which you do that over four releases, you end up with five times faster, right?
That's the standard plan.
Where are we on this?
How's it going for you and everyone on the team?
I say it's a bit of a jumble of stages one and two that we're implementing, largely because it's a larger, more diverse team than I was expecting.
So it makes sense to just sort of spread things.
Yeah.
You'll work on operators, you go work on zero overhead exception handling and so on.
Yeah.
So I would say from where we are now, I was probably a bit optimistic with stage one, but stage two seems to have a lot of potential still.
There's always little bits of the interpreter we can tweak and improve.
So between the two of them, I'm confident we'll get this projected over twice the speed.
That's fantastic.
So the course you're on right now, if let's just say stage one and two happen, and for some reason the JET stuff doesn't, that's still a big contribution.
What do you think in terms of speed up for that?
Well, again, it's going to depend a lot.
I know it matters so much, but like, you know.
I mean, I just want to, because like currently we have a sort of set of benchmarks that we're using.
I mean, not possibly the, I mean, the more benchmarks is always better.
So it's a broad set.
Individually, the benchmarks, some of them aren't great, but collectively a form a sort of useful data set.
But I mean, we speed up from up like up to 60% down to zero.
So it's definitely a spread.
So it can, you know, try it out would be the thing.
I mean, you can download 3.11 Alpha 1 and Alpha 2 should be out a few days at all time now.
It's presumably before you publish a podcast.
Yeah.
Fantastic.
So people can download it, play it with it.
Yeah, that's fantastic.
You know, thank you for this.
I think even 50, 60%, if it stayed there, that's pretty incredible.
I mean, this language has been around for 30 years.
People have been trying to optimize it for a long time.
It's incredible, right?
And then, you know, to do this sort of change now, that would be really significant.
Yeah.
This is an area that we haven't spent much time on previously for various reasons.
I mean, people have spent a lot of time on sort of making the string of the objects fast,
making dictionary operations fast, making the memory efficient, adding functionality that
the sort of Python has generally, I think, had more of a focus on functionality than on speed.
And so for me, this is also a change in mindset.
I'm still learning a lot.
Mark actually teaches me a lot about how to think about this stuff.
And I decided to buy this horrible book.
Well, it's a great book.
Computer architecture.
But it's also like it weighs more than a 17-inch laptop.
Wow.
Classic text, but not a light read.
Yeah.
Down into beyond the software layer, into the hardware bits.
It makes me amazed that we have any performance at all and that any performance is predictable
because we're doing everything wrong from the perspective of giving the CPU something to work with.
I mean, all the algorithms described in there, branch prediction, speculative execution,
caching of instructions, all that is aimed at small loops of numerical code.
And we have none of that.
Yeah.
Exactly.
C of LC is not a numerical loop.
Definitely not.
All right.
Well, I think that might be it for the time we have.
I got a couple of questions from the audience out there.
Toon Army Captain says, I'm interested in Guido's thoughts about the Microsoft funded effort
versus the developer in residence, particularly in terms of the major work of the language and
the CPython runtime going forward.
I think these are both good things, both really good things.
They seem super different to me.
I think it's great that we have a developer in residence.
It's a very different role than what we're doing here.
The team at Microsoft is at least we're trying to be super focused on performance to the exclusion
of almost everything else, except all those constraints I mentioned, of course.
The developer in residence is focused on sort of the community, other core developers, but
also contributors.
Lukasz is great.
He's the perfect guy for that role.
And his work is completely orthogonal to what we're doing.
I hope that somehow the PSF finds funds for keeping the developer in residence role and
maybe even expanding it for many years.
seems to me like a really important role to smooth the edges of people contributing to
CPython.
And the difference of what Mark and you all are doing is heads down, focused on writing
one type of code, whereas Lukasz is there to make it easier for everyone else to do whatever
they were going to do.
Right.
And I think, you know, one sort of a horizontal scale of the CPython team and the other is very
focused, which is also needed.
It's actually amazing that we've been able to do all the work that we've been doing over
the past 30 years on Python without a developer in residence.
I think in the early years, I was probably taking up that role.
But the last decade or two, there just have been too many issues, too many peps for me to
sort of get everything going and sort of having...
I was always working part time on Python and part time working on my day job.
Right.
Absolutely.
Lukasz is working full time on Python.
And he has a somewhat specific mandate to sort of help people, help sort of contributions
go smoother, make working with the issue tracker easier.
So and that sort of developer contributors must be encouraged and rewarded.
And currently, often the way the bugs.python.org experience is it's a very old web app and it
looks that way.
And it's difficult to learn how to do various things with that thing.
And so Lukasz is really helping people.
Yeah, it's fantastic.
With the edges.
Of course, there's also the somewhat separate project of switching from bugs.python.org to
a purely GitHub-based tracker.
Yeah, I was just thinking of that as you were speaking there.
Do you think that'll help?
I feel like people are more familiar with that workflow.
People are more familiar.
It's more integrated with the pool request flow that we already have on GitHub.
I think it will be great.
Expectations is that I think it will be actually happening before the end of this year or very
early next year.
That'd be fantastic.
The code's already there.
The work's already there.
Might as well have the conversations and the issues and whatnot there.
All right, guys.
I think we are definitely over time, but I really appreciate, first of all, the work
that you're doing, Mark, on this project and Guido on the last 30 years.
This is amazing.
You can see out in the comments how appreciative folks are for all the work you've done.
So thank you for that.
Let's close with a final call to action.
You have the small team working on it.
I'm sure the community can help in some way.
What do you want from people?
How can they help you either now or in the future?
I mean, it's just contribute to CPython.
So, I mean, I don't think it's specifically performance.
I mean, like all the contributions help improve, you know, co-quality and reliability are still
very important.
So I don't think particularly people can do.
But we do have a sort of ideas repo if people do have sort of things they want to suggest
or bounce ideas around, whatever.
Maybe they could test their workloads on alpha versions of things like that.
Yeah, I mean, that would be fantastic.
I mean, we don't really have a set for where people can put that information.
But if just open an issue on the ideas thing and post some data, it'd be fantastic.
We'd love it for people to try to use the new code and see how it works out for them.
Yeah, fantastic.
All right.
Well, thank you both for being here.
It's been great.
Our pleasure.
Thank you.
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.
Choose Shortcut, formerly Clubhouse.io, for tracking all of your project's work.
Because you shouldn't have to project manage your project management.
Visit talkpython.fm/shortcut.
Simplify your infrastructure and cut your cloud bills in half with Linode's Linux virtual machines.
Develop, deploy, and scale your modern applications faster and easier.
Visit talkpython.fm/linode and click the Create Free Account button to get started.
Do you need a great automatic speech-to-text API?
Get human-level accuracy in just a few lines of code.
Visit talkpython.fm/assemblyai.
Want to level up your Python?
We have one of the largest catalogs of Python video courses over at Talk Python.
Our content ranges from true beginners to deeply advanced topics like memory and async.
And best of all, there's not a subscription in sight.
Check it out for yourself at training.talkpython.fm.
Be sure to subscribe to the show.
Open your favorite podcast app and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play, and the direct
RSS feed at /rss on talkpython.fm.
We're live streaming most of our recordings these days.
If you want to be part of the show and have your comments featured on the air, be sure to subscribe
to our YouTube channel at talkpython.fm/youtube.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
I'll see you next time.
Thank you.