This seems like excellent, pragmatic stewardship by the steering council! It's unfortunate that such an interesting feature didn't clear the threshold for being fully incorporated, but the JIT proponents are always free to fork/look to another runtime for integration and experimentation, before potentially re-engaging with the CPython team again!
i can here to see this, I was guessing 12 years or so.. but maybe i'm remembering wrong... I remember talks of GIL removal under a name of unladen swallow, which looking was 2010.
I agree.. It might really be time to be done with it...
GIL removal isn't the same thing as JIT. The GIL removal project is now known as free-threaded Python, and that's shipped in 3.13, 3.14, and 3.15 and will continue in 3.16.
Looks like a death by bureaucracy to me. Basically the JIT was gathering a lot of steam/community attention, then the steering committee started demanding a bunch of paperwork to approve it.
Reading the motivation for the withdrawal pretty much confirms that the steering committee burned out the developers working on it.
Very disappointing to see this happen. Don't really get the praise for the process, this entire thing just reeks of the steering committee getting upset that something is being worked on without their explicit approval stamp, it getting a lot of positive attention in the press (the JIT was talked about by tech news in much the same breath as fixing up the GIL), and subsequently choosing to ruin it for everyone.
The PEP process has mostly been good at iteratively improving the language, but it's always struggled at fixing up some of the worse fundamentals of Python. There's a reason why python3k/python 3 had to basically get crowbarred through by BDFL edict. Sometimes the sheer volume of paperwork processes like this demand doesn't square well with the actual work involved.
Disclaimer: I know nothing of the JIT work and how it progressed (but I read the linked article).
An alternative explanation that is also entirely reasonable is that the JIT experiment didn't work (does not actually provide benefits as strong as hoped, and has a large cost in terms of engineering and maintenance and security concerns and compatibility-with-the-rest-of-the-ecosystem). But instead of saying out loud that the JIT work is turning out to be a failure, which would be negative and a criticism of the brave developers involved, the steering council phrased this in terms of decision processes and documents, and as a result the justification for the removal sounds bureaucratic.
You write that "the JIT was gathering a lot of attention", in the community and in the process. Okay, but we have all seen promising faster-python projects get a lot of attention and then get shot down when they turn into slow quagmire. Can you share references that indicate that the project was actually succeeding at its goals, and that the advantages of having it were higher than the cost of having it?
I don't have a direct reference; that said if you read the Steering Committee thread one of the main concerns raised by a core developer is that the JIT was actually generating a lot of PRs and was a source for onboarding new developers (the announcement came along with the SC demanding a forced pause on any and all JIT contributions). It makes it look like the Steering Council deliberately tried to kill the JIT off right as it was gaining traction. Not helping matters is that the SC members have a reaction to being told this that amounts to "fork it off to a separate branch then", when "just fork Cython" is historically how the Python project has killed off incentives it doesn't want/like.
It all combines to me concluding that new people were contributing in part because the JIT was an easy way to get familiar with contributing to Cython and actually getting those changes in a final release. (This isn't uncommon; helping people work on large "low hanging fruit" is often how you can get new contributors in FOSS projects.) Then the SC suddenly steps in to effectively put a stop to it; why would you want to contribute when a fairly distant committee can just decide that everything you've put time and effort into isn't worth it. I can't read it as anything other than the SC choosing to insulate Cython from new developers, even as Cython devs themselves want to being in new developers. Hence, death by bureaucracy.
Said thread also reports several performance increases and the fact the JIT itself was already designed for long-term maintenance from the beginning (focusing on easier to use structures so that volunteers could maintain it, rather than engineers).
Over the years I’ve strongly had the impression that the CPython project and by extension Python foundation exist for the convenience of the long time developers and their interests, and everything pretty much makes sense if you view as being for the entertainment and interests of those developers.
I’m not saying there’s something intrinsically wrong with that, but most people seem to assume that they’re acting in the interests of the “Python community”. Unfortunately this has left pypy playing catchup, and presumably any fork of CPython trying to do jit would presumably suffer from at least some of the same headwinds.
I don't really understand. Aren't JITs good at optimizing things that look like Python (or for example, what draws me to think that, Java)? Or is Python that unoptimizable such that people are giving up? Was the JIT effort not worth it, and if it wasn't, for what reason it was introduced, and for what reason is it going away?
Python itself is optimizable, PyPy proves it.
Python-the-way-its-used-in-the-real-world it's a very different beast though. I claim that it's de facto impossible to write a Pyhon implementation which is fast ("real fast", not 10% faster than CPython) and backwards compatible.
I talked about at EuroPython 2025, here are the slides and the video: https://antocuni.eu/talk/2025/07/europython-myths-and-fairy-tales/
JITs aren't inherently "good at" anything other than eliminating bytecode instruction dispatch cost, which isn't where most of Python's slowness comes from. You need to build out a system to track common runtime shapes of values, you need a system to build monomorphized versions of functions for common input shapes and bail out if a monomorphized function detects that the input isn't of the expected shape, and on top of that you need a good optimizing compiler back-end. All of that is a lot of work which can be done better and worse.
JITs can be good at optimizing things that look like Python, but they don't have to be. If you have a decade and a team of dedicated compiler engineers you'll get something with excellent performance. If you do the bare minimum to have something that's legitimately a JIT you'll have maybe a couple percent performance improvements from not having to spend time dispatching to the right code block for every bytedoce instruction.
I wrote about such a "minimum effort" JIT compiler here: https://mort.coffee/home/fast-interpreters/#h2-final-step-a-compiler -- it takes the C code that you'd be dispatching to and generates it instead, then compiles it with GCC. Now I see a huge speed-up with my toy bytecode language but that's because it's low level; an add instruction is, "pop two 32-bit ints from the stack, add them, push the resulting 32-bit int onto the stack". As a result, just getting rid of the dispatch overhead is a huge win. Python's add instruction is more, "pop two object references off the stack, do a hash map lookup for the string __add__ on the first object's class, call the resulting function with the two object references as parameters, push the return value to the stack". That's such a monumental amount of work that it dwarfs the time it takes to dispatch.
JITs aren't inherently "good at" anything other than eliminating bytecode instruction dispatch cost
Instruction dispatch usually isn't the only or the most expensive part of an interpreter compared to JIT-compiled code, it's also that all values, including constants, are practically forced into memory and need be referenced indirectly. Having fewer stores/loads and being able to use registers can give similar performance improvements like eliminating the dispatch overhead. Store-to-load-forwarding of CPUs can't keep up with the amount of stores/loads and memory renaming (where the CPU keeps the physical register of a stored value for a later load) doesn't work, because it is not trainable on the interpreter code.
Can people in the know elaborate more on why JIT runtimes like HotSpot (Java), V8 (JavaScript) (as well as the runtimes in other browsers), ZJIT (Ruby) could be realized and maintained, even in PHP (!) of all languages, whereas it does not seem to work out in the case of Python, beyond what has been already described in the article? Clearly, when enough resources are poured, the likes of V8 could be built and maintained. Why isn't there enough interest from.. those (big businesses, institutions and so on) who might benefit.. to hire relevant/qualified people to work on this, than relying on the (finite) energy of volunteers entirely..? Is this emblematic of the state of FOSS in general?
I will add that among your examples, Ruby and Python are in the different class of languages from Java and JavaScript, for reasons described in https://blog.kevmod.com/2016/07/02/why-is-python-slow/ --- a lot of code that's being executed is the C code of the interpreter itself.
Beyond what matklad has described, I think another complicating factor is that a substantial portion of Python's ecosystem depends on native extensions and those extensions have been (and still are, I think?) deeply intertwined with CPython implementation details. This tends to make things interesting for JITs which may want/need different internal structures for performance reasons.
For example, PyPy has long been able to show decent speedups over CPython... as long as you're using pure Python code. Once you start dealing with native extensions, though (assuming they're even compatible in the first place), you can see that speedup shrink quite significantly (or even go negative depending on what you're doing) due to PyPy needing to pessimize and/or do extra work to provide a compatible interface for the extension.
This kind of thing isn't exclusive to Python - Java's JNI has a per-call overhead (though IIRC the new foreign function interfaces are supposed to be somewhat better?), C extensions present optimization barriers to Ruby's YJIT, etc. However, languages like Java and JavaScript rely far less on native extensions than Python does and so that particular pain point doesn't affect them nearly as badly. I'm admittedly not as familiar with Ruby and PHP's ecosystems so I don't know how far this extends to them, though.
For example, PyPy has long been able to show decent speedups over CPython... as long as you're using pure Python code. Once you start dealing with native extensions, though (assuming they're even compatible in the first place), you can see that speedup shrink quite significantly (or even go negative depending on what you're doing) due to PyPy needing to pessimize and/or do extra work to provide a compatible interface for the extension.
An important addendum here is that when pure Python versions exists it does not necessarily run anywhere near C speed (even straightforward non-fancy C), and that extends to the stdlib (a few years back I learned that re is horribly slow under pypy, we’re talking orders of magnitude, which is a problem if your project is mostly regex matching).
An other one is that the tricks to optimise cpython and pypy are not always compatible.
conor | 20 hours ago
This seems like excellent, pragmatic stewardship by the steering council! It's unfortunate that such an interesting feature didn't clear the threshold for being fully incorporated, but the JIT proponents are always free to fork/look to another runtime for integration and experimentation, before potentially re-engaging with the CPython team again!
dmpk2k | 18 hours ago
There's been attempts at a Python JIT for over two decades now. It's probably time to just stick a fork in it.
Student | 18 hours ago
In fairness the pypy jit does speed up real workloads
sigmonsez | 16 hours ago
i can here to see this, I was guessing 12 years or so.. but maybe i'm remembering wrong... I remember talks of GIL removal under a name of unladen swallow, which looking was 2010.
I agree.. It might really be time to be done with it...
simonw | 3 hours ago
GIL removal isn't the same thing as JIT. The GIL removal project is now known as free-threaded Python, and that's shipped in 3.13, 3.14, and 3.15 and will continue in 3.16.
noirscape | 16 hours ago
Looks like a death by bureaucracy to me. Basically the JIT was gathering a lot of steam/community attention, then the steering committee started demanding a bunch of paperwork to approve it.
Reading the motivation for the withdrawal pretty much confirms that the steering committee burned out the developers working on it.
Very disappointing to see this happen. Don't really get the praise for the process, this entire thing just reeks of the steering committee getting upset that something is being worked on without their explicit approval stamp, it getting a lot of positive attention in the press (the JIT was talked about by tech news in much the same breath as fixing up the GIL), and subsequently choosing to ruin it for everyone.
The PEP process has mostly been good at iteratively improving the language, but it's always struggled at fixing up some of the worse fundamentals of Python. There's a reason why python3k/python 3 had to basically get crowbarred through by BDFL edict. Sometimes the sheer volume of paperwork processes like this demand doesn't square well with the actual work involved.
gasche | 15 hours ago
Disclaimer: I know nothing of the JIT work and how it progressed (but I read the linked article).
An alternative explanation that is also entirely reasonable is that the JIT experiment didn't work (does not actually provide benefits as strong as hoped, and has a large cost in terms of engineering and maintenance and security concerns and compatibility-with-the-rest-of-the-ecosystem). But instead of saying out loud that the JIT work is turning out to be a failure, which would be negative and a criticism of the brave developers involved, the steering council phrased this in terms of decision processes and documents, and as a result the justification for the removal sounds bureaucratic.
You write that "the JIT was gathering a lot of attention", in the community and in the process. Okay, but we have all seen promising faster-python projects get a lot of attention and then get shot down when they turn into slow quagmire. Can you share references that indicate that the project was actually succeeding at its goals, and that the advantages of having it were higher than the cost of having it?
noirscape | 15 hours ago
I don't have a direct reference; that said if you read the Steering Committee thread one of the main concerns raised by a core developer is that the JIT was actually generating a lot of PRs and was a source for onboarding new developers (the announcement came along with the SC demanding a forced pause on any and all JIT contributions). It makes it look like the Steering Council deliberately tried to kill the JIT off right as it was gaining traction. Not helping matters is that the SC members have a reaction to being told this that amounts to "fork it off to a separate branch then", when "just fork Cython" is historically how the Python project has killed off incentives it doesn't want/like.
It all combines to me concluding that new people were contributing in part because the JIT was an easy way to get familiar with contributing to Cython and actually getting those changes in a final release. (This isn't uncommon; helping people work on large "low hanging fruit" is often how you can get new contributors in FOSS projects.) Then the SC suddenly steps in to effectively put a stop to it; why would you want to contribute when a fairly distant committee can just decide that everything you've put time and effort into isn't worth it. I can't read it as anything other than the SC choosing to insulate Cython from new developers, even as Cython devs themselves want to being in new developers. Hence, death by bureaucracy.
Said thread also reports several performance increases and the fact the JIT itself was already designed for long-term maintenance from the beginning (focusing on easier to use structures so that volunteers could maintain it, rather than engineers).
Here's that thread, although it's also linked in the LWN post.
sloane | 11 hours ago
CPython and Cython are two different projects, just fyi.
Student | 9 hours ago
The iron law of institutions in effect https://rationalwiki.org/wiki/Iron_law_of_institutions
Student | 9 hours ago
Over the years I’ve strongly had the impression that the CPython project and by extension Python foundation exist for the convenience of the long time developers and their interests, and everything pretty much makes sense if you view as being for the entertainment and interests of those developers.
I’m not saying there’s something intrinsically wrong with that, but most people seem to assume that they’re acting in the interests of the “Python community”. Unfortunately this has left pypy playing catchup, and presumably any fork of CPython trying to do jit would presumably suffer from at least some of the same headwinds.
gunduzc | 16 hours ago
I don't really understand. Aren't JITs good at optimizing things that look like Python (or for example, what draws me to think that, Java)? Or is Python that unoptimizable such that people are giving up? Was the JIT effort not worth it, and if it wasn't, for what reason it was introduced, and for what reason is it going away?
antocuni | 14 hours ago
Python itself is optimizable, PyPy proves it. Python-the-way-its-used-in-the-real-world it's a very different beast though. I claim that it's de facto impossible to write a Pyhon implementation which is fast ("real fast", not 10% faster than CPython) and backwards compatible. I talked about at EuroPython 2025, here are the slides and the video: https://antocuni.eu/talk/2025/07/europython-myths-and-fairy-tales/
mort | 10 hours ago
JITs aren't inherently "good at" anything other than eliminating bytecode instruction dispatch cost, which isn't where most of Python's slowness comes from. You need to build out a system to track common runtime shapes of values, you need a system to build monomorphized versions of functions for common input shapes and bail out if a monomorphized function detects that the input isn't of the expected shape, and on top of that you need a good optimizing compiler back-end. All of that is a lot of work which can be done better and worse.
JITs can be good at optimizing things that look like Python, but they don't have to be. If you have a decade and a team of dedicated compiler engineers you'll get something with excellent performance. If you do the bare minimum to have something that's legitimately a JIT you'll have maybe a couple percent performance improvements from not having to spend time dispatching to the right code block for every bytedoce instruction.
I wrote about such a "minimum effort" JIT compiler here: https://mort.coffee/home/fast-interpreters/#h2-final-step-a-compiler -- it takes the C code that you'd be dispatching to and generates it instead, then compiles it with GCC. Now I see a huge speed-up with my toy bytecode language but that's because it's low level; an add instruction is, "pop two 32-bit ints from the stack, add them, push the resulting 32-bit int onto the stack". As a result, just getting rid of the dispatch overhead is a huge win. Python's add instruction is more, "pop two object references off the stack, do a hash map lookup for the string
__add__on the first object's class, call the resulting function with the two object references as parameters, push the return value to the stack". That's such a monumental amount of work that it dwarfs the time it takes to dispatch.aengelke | an hour ago
Instruction dispatch usually isn't the only or the most expensive part of an interpreter compared to JIT-compiled code, it's also that all values, including constants, are practically forced into memory and need be referenced indirectly. Having fewer stores/loads and being able to use registers can give similar performance improvements like eliminating the dispatch overhead. Store-to-load-forwarding of CPUs can't keep up with the amount of stores/loads and memory renaming (where the CPU keeps the physical register of a stored value for a later load) doesn't work, because it is not trainable on the interpreter code.
kel | 15 hours ago
You should read the article, it answers your questions.
asem | 14 hours ago
Another year of solving Advent of Code with PyPy then 🙂
smlckz | 14 hours ago
Can people in the know elaborate more on why JIT runtimes like HotSpot (Java), V8 (JavaScript) (as well as the runtimes in other browsers), ZJIT (Ruby) could be realized and maintained, even in PHP (!) of all languages, whereas it does not seem to work out in the case of Python, beyond what has been already described in the article? Clearly, when enough resources are poured, the likes of V8 could be built and maintained. Why isn't there enough interest from.. those (big businesses, institutions and so on) who might benefit.. to hire relevant/qualified people to work on this, than relying on the (finite) energy of volunteers entirely..? Is this emblematic of the state of FOSS in general?
matklad | 13 hours ago
See https://lobste.rs/s/9ex6hs/reflections_on_2_years_cpython_s_jit#c_oo2tyk
I will add that among your examples, Ruby and Python are in the different class of languages from Java and JavaScript, for reasons described in https://blog.kevmod.com/2016/07/02/why-is-python-slow/ --- a lot of code that's being executed is the C code of the interpreter itself.
aw1621107 | 7 hours ago
Beyond what matklad has described, I think another complicating factor is that a substantial portion of Python's ecosystem depends on native extensions and those extensions have been (and still are, I think?) deeply intertwined with CPython implementation details. This tends to make things interesting for JITs which may want/need different internal structures for performance reasons.
For example, PyPy has long been able to show decent speedups over CPython... as long as you're using pure Python code. Once you start dealing with native extensions, though (assuming they're even compatible in the first place), you can see that speedup shrink quite significantly (or even go negative depending on what you're doing) due to PyPy needing to pessimize and/or do extra work to provide a compatible interface for the extension.
This kind of thing isn't exclusive to Python - Java's JNI has a per-call overhead (though IIRC the new foreign function interfaces are supposed to be somewhat better?), C extensions present optimization barriers to Ruby's YJIT, etc. However, languages like Java and JavaScript rely far less on native extensions than Python does and so that particular pain point doesn't affect them nearly as badly. I'm admittedly not as familiar with Ruby and PHP's ecosystems so I don't know how far this extends to them, though.
masklinn | 2 hours ago
An important addendum here is that when pure Python versions exists it does not necessarily run anywhere near C speed (even straightforward non-fancy C), and that extends to the stdlib (a few years back I learned that re is horribly slow under pypy, we’re talking orders of magnitude, which is a problem if your project is mostly regex matching).
An other one is that the tricks to optimise cpython and pypy are not always compatible.