NewsLab
Oct 28 17:11 UTC

Python's experimental JIT to be removed (lwn.net)

554 points|by f311a||306 comments|Read full story on lwn.net

Comments (306)

120 shown|More comments
  1. 1. bratao||context
    This is pretty bittersweet to see.

    Python is my favorite language, but I'm honestly tired of having to rewrite performance bottlenecks in Cython or Rust all the time. When the Faster CPython project started with Microsoft's backing, I was really excited. Mark Shannon had that plan promising huge speedups across a few cycles, and while that clearly turned out to be much harder than anticipated, the team still kept pushing forward to deliver a real JIT.

    Seeing all of that get bogged down in committee bureaucracy now is just frustrating.

    I have a lot of respect for the core devs and I know maintaining CPython, and it is a time donation job. It isn't easy. But I feel that over-caution and red tape ends up discouraging serious contributions. They are setting an unreasonably high bar for something that would obviously help the entire ecosystem.

    Just think about the sheer amount of electricity and compute power being wasted every single day running inefficient Python across millions of machines worldwide.

    Python really deserves a proper JIT. I genuinely hope they reconsider this.

  2. 2. mananaysiempre||context
    Unladen Swallow died for lack of upstream interest.

    PyPy lacks upstream interest, looked like it could have a shot after many years of development but recently NumPy removed support because they just couldn’t fathom how a non-dead project could be a couple of versions behind CPython.

    Now the new JIT is dying because of what seems to be a lack of upstream interest. (The things TFA describes as being required are not unreasonable, but not realistic for a necessarily speculative long-running project without wild amounts of committed funding.)

    I’m not optimistic.

  3. 3. pansa2||context
    > Unladen Swallow died for lack of upstream interest

    IIRC Unladen Swallow was, despite the extreme hype, nothing more than the internship project of a couple of students. It died because their internship was over.

    Otherwise you're right, though. Lots of CPython alternatives suffer from lack of upstream interest - the Python language designers don't seem very interested in anything other than CPython. In particular, they appear to only consider CPython when adding features to the language. Two examples:

    - Requiring `dict`s to be ordered because that's how they work in CPython, without considering how they work in other implementations

    - Adding pattern matching syntax that's suitable for CPython's PEG parser, even though it's not LL(1) so can't be parsed by, say, MicroPython

  4. 4. genxy||context
    Core Python is antagonistic to all other Python implementations. There is only one Python.
  5. 5. ZiiS||context
    I know not everyone loves them; but `Claude rewrite the performance bottlenecks in Rust` works so well it is hard to see the security surface area and harder reason about performance as something that should be paid in core.
  6. 6. greenavocado||context
  7. 7. ddorian43||context
    Seems unmaintained from July.
  8. 8. greenavocado||context
    I think its a meme but an interesting proof of concept nevertheless
  9. 9. skeledrew||context
    > committee bureaucracy

    That's what's kept the language and ecosystem improving and from becoming a hot mess. If something isn't properly specced then it really shouldn't be in prod. They allowed the experiment in the first place so it'd be easier to gather sufficient data to guide said speccing, but the ball was dropped by the proposers and so the experiment was an ultimate failure (unlike free threading) and prod is now being appropriately cleaned up.

  10. 10. pjmlp||context
    > Just think about the sheer amount of electricity and compute power being wasted every single day running inefficient Python across millions of machines worldwide.

    Every single time I remember the first AI wave was done with Lisp and Prolog, both with tooling that supports machine code generation since about 50 years.

  11. 11. samus||context
    It's not red tape, it's about making sure that the effort actually delivers what it promises and can continue to so in the future. From the state of the draft PEP it seems it doesn't and it won't ever. The SC merely put the nail into the coffin.
  12. 12. xx_ns||context
    It's unfortunate that a technically exciting new feature is being killed partly because of what is essentially bureaucracy (and the lack of the developer's personal bandwidth). On the other hand, it's pretty safe to say that the strict adherence to the PEP policy and all of the bureaucracy that comes with it is what makes Python a great language, for better or worse.

    Not to say that the technical objections were without merit, they likely very much weren't, and the debugger and instrumentation support and maintenance work sounds fairly painful on its own.

  13. 13. Good4boothee||context
    Looking at amount of JIT related (for example type confusion) security bugs in V8 I am not surprised other developers are vary of its inclusion.
  14. 14. jeremyjh||context
    I think it would be a mistake to conclude this has anything at all to do with bureaucracy as a matter of inanimate policy that the SC was helplessly in thrall to. Bureaucracy was the tool the SC used to demonstrate that this feature lacked many important properties that they cared about, as mentioned: "maintenance, compatibility, and ... clear success metrics". For whatever detailed reasons, the PEP was withdrawn after it couldn't convincingly demonstrate those things to the satisfaction of the critics on the SC.
  15. 15. bunderbunder||context
    Im not sure I even like calling it bureaucracy. It’s a process, yes. But we’re not talking many layers of abstract organizational hell, here. Were talking a fairly direct process of documenting what you are doing and how you are going to do it well enough that others working and depending on the project can understand it, coordinate with it, and have a reasonable degree of confidence that it won’t cause undue problems.

    If having to put all that in writing and get a bunch of people to agree feels too burdensome to you, maybe that’s a sign that you would be happier working on something other than core changes to the world’s second most popular programming language.

    (edit: That wasn’t meant to be a jab at the core developers working on the JIT. Based on what’s in the public discussion threads, they have been handling things very well throughout the process. It’s unfortunate that the SC let the project get this far before realizing the project had grown well beyond its original PIP’s mandate, and I’m sure that is deeply frustrating to the people leading the project. I know I would not be handling the setback nearly as gracefully as they are.)

  16. 16. vlovich123||context
    The problem is that clearly documenting all details as required in the PEP is at odds with complicated new features like a JIT where all the details can’t be known and have to be decided on as they are realized. Process / bureaucracy is at direct odds with experimentation.
  17. 17. jeremyjh||context
    What are you basing this statement on?

    The experiments had long been done. The topic at hand was including it as a core feature.

  18. 18. bunderbunder||context
    But they weren’t asking for all the implementation details. They were asking for a clearly stated scope, success criteria, support plan, etc.

    As they themselves pointed out, the problem isn’t that there’s anything wrong with an open-ended experiment. It’s just that open-ended experimentation doesn’t belong in main, of all places. They have an ongoing duty to ensure that a critical piece of global infrastructure remains stable and trustworthy to consider.

  19. 19. cogman10||context
    > clearly stated scope

    The scope of a JIT is the entire python runtime. Not at the beginning, it can be more narrow, but certainly it can evolve to cover everything. JITs touch everything.

    > success criteria

    Impossible to measure. JITs don't universally make things faster and unless the SC was willing to accept "some programs will see around x% improvement" then it would be impossible to actually give them the criteria they want. There's a reason C++ compilers and their optimizations aren't defined by the ISO committee.

    > support plan

    Like most JITs, support for a JIT is an ongoing and ever evolving process. What's needed depends entirely on what's needed today. You usually need more than 1 or 2 dev working on it, which may be the issue here.

    > It’s just that open-ended experimentation doesn’t belong in main, of all places.

    Very strong disagree. That's simply the nature of performance optimizations for JITs. They belong on main because new optimizations and heuristics will always be generated. The role of doing a compiler is a long term experiment in performance, seeing what your runtime is currently doing and how it's being used and tweaking it to work better.

    pypy isn't in a worse place because it's been running a longterm performance experiment.

    > They have an ongoing duty to ensure that a critical piece of global infrastructure remains stable and trustworthy to consider.

    None of the things mentioned actually do that, other than perhaps a support plan. There are plenty of critical infrastructure projects who all can manage to develop JITs. Python is the special snowflake that has decided to do JIT development incorrectly.

    This is a runtime optimization/implementation detail. It's foolish to send it through a committee approval process. That's why you won't be able to find a single language with a JIT or advanced optimizations that has do it by committee.

  20. 20. ModernMech||context
    In that case I can understand why it's not a fit for Python. The risks you're describing are more what a brand new language would face: universal scope, impossible to measure success, no support plan... sounds like a nightmare in a mature product. If that's actually what it means to add a JIT to Python, the SC is doing its job by steering Python around this quixotic task.

    > This is a runtime optimization/implementation detail.

    I view JITs as a critical architectural component. Like you said, it impacts the whole system. Optimization and implementation details don't usually do that.

  21. 21. vlovich123||context
    The problem is that “Python” the language includes native poorly isolated FFI interfaces exposed by CPython. So the language isn’t “Python” but CPython. That’s why alternate implementations like PyPy haven’t seen adoption despite having a very mature JIT while languages like JavaScript have JITs that put CPython’s performance to shame.
  22. 22. bunderbunder||context
    It’s also part of why Python has been so successful in many domains. I was there for Python’s takeover of the data space, and I got quite used to porting things from Java (static, JIT, decent at multithreading) to Python (dynamic, interpreted, GIL) and realizing substantial performance improvements in the process.

    It’s kind of wild how nice Python’s C extension system, which enables basically zero cost interop with native code, is for certain purposes. It supports a situation that’s comparable to the games industry’s tradition of putting a Lua or Lisp tip on top of a C++ iceberg.

  23. 23. bunderbunder||context
    And yet, not introducing unnecessary chaos into the CPython project remains important.

    Perhaps these priorities were always irreconcilable.

    Perhaps that’s why the existence of competing Python JIT projects that weren’t trying to commit directly into CPython’s main branch kept coming up in the conversation.

  24. 24. saghm||context
    > Im not sure I even like calling it bureaucracy. It’s a process, yes. But we’re not talking many layers of abstract organizational hell, here. Were talking a fairly direct process of documenting what you are doing and how you are going to do it well enough that others working and depending on the project can understand it, coordinate with it, and have a reasonable degree of confidence that it won’t cause undue problems.

    Bureaucracy doesn't definitionally mean Kafkaesque. It's popular to hate on it, but good or neutral bureaucracy does exist.

  25. 25. bunderbunder||context
    It doesn’t have to mean kafkaesque, but it does mean governance through layered hierarchies and fixed procedures.

    In this case a single committee directly engaged with both core developers and the community, through a fairly open process, explicitly bent several of their own official rules to suit the occasion, and indicated cases where further flexibility might be needed depending on how things develop.

    I would call that a pretty stellar example of non-bureaucratic governance.

  26. 26. saghm||context
    Fair enough. I was reacting more to the "organizational hell" part and didn't focus as much on the "layers" part.
  27. 27. bunderbunder||context
    I have a hard time seeing it as organizational hell, either? From the outside, it looks like the process went smoothly and reached a decision in about half the time they originally estimated.

    It’s true that that decision didn’t involve everybody getting their way. But that’s not organizational hell, that’s just organization. If you don’t want to contend with other people’s competing interests, the solution to that is solo development.

  28. 28. dcss_gardener||context
    HN when AI is used to bomb a school: technology is neutral.

    HN when an organization achieves its intended goals: this can't be bureaucracy because it's good.

  29. 29. pphysch||context
    Large codebases are bureaucracies of their own, that is, the complexity of extra layers starts to bog things down at some point.

    In this case, it seems like the human bureaucracy made wise and measured decisions to contain the software bureaucracy. They made reasonable requests to clarify the scope and impact of a major, major core feature. The proposers didn't feel like that was doable, so a complexity nuke was avoided.

  30. 30. kannanvijayan||context
    Gonna dump a technical hot take here.

    Python is a mature production language with a lot of users. Even before it was huge - like 20 years ago when I was in college - getting a small backwards compatible API change into a python extension module (gnu readline in my case) required convincing GvR personally that the API change was necessary.

    Every JIT attempt I've seen for python just tries to cut too deep in the first pass, and scope themselves too large.

    I believe any successful attempt at optimizing python performance from JIT will FIRST start with a 100% semantically compatible hidden type model for optimizing object property access and method dispatch.

    The single biggest performance delta in most dynamic language jits come from that, not from optimizing guards off of bytecode operations or from compiling to machine code. It's from converting hashtable lookups into constant-time guard + offset lookups.

    The hidden type model is also a hard nut to crack. It needs to perserve dict semantics which have very dynamic behaviour via the various `__*__` methods, and handle exotics scope objects since scoped name lookups are the most common ones which have their own exotic behaviours (I remember python providing some ability for callee frames to inspect caller scopes in some limited ways).

  31. 31. Pxtl||context
    It still blows my mind that the big "we're breaking backwards compatibility Python 3000" release didn't do anything to lay the groundwork for this, or any of Python's other structural problems.
  32. 32. jeremyjh||context
    Its possible this could have been the concrete pillar that broke the camel's back and set Python 3 on the path of Perl 6.
  33. 33. ModernMech||context
    At the time, Python had a clear purpose as an easy to learn "glue" language between other, perhaps more performant languages. There was no reason to make Python as fast because that would muddy its purpose by introducing compromises and complexity. For better or worse Python sat pretty well in its niche.

    Today there are far more people using it, and everyone has a different perspective on what it is. No longer is it a niche glue language, now it's a backbone of AI technology at major tech firms, so it's understandable they'd like it to be faster on its own.

  34. 34. 0xpgm||context
    For a long time Guido wanted CPython to remain simple, as the reference implementation.

    Probably also during the 2 to 3 migration, but that goal appears to have now been abandoned.

    I wonder how the authors of other implementations like pypy will be able to keep up as the reference implementation becomes more and more complex.

  35. 35. Pxtl||context
    > the reference implementation.

    The problem was he exposed too much of the implementation into the language itself, destroying its ability to be a simple reference implementation that others could re-implement.

  36. 36. mohamedkoubaa||context
    This is slowly being addressed now, each version of Python sees the c API become more opaque.
  37. 37. twoodfin||context
    Are there any PEPs that describe this work?
  38. 38. iqbal1980||context
    They reference this one in the article https://peps.python.org/pep-0836/
  39. 39. twoodfin||context
    I meant the trend of making the C interop more opaque.
  40. 40. mohamedkoubaa||context
    See the stable ABI for Python 3.15 and PEP 793, 803, 820 for recent movements in this general direction and the following draft: https://github.com/py-ni/peps/blob/main/peps/pep-08xx.rst (the py-ni project is pushing for this)
  41. 41. jsmith45||context
    That's at best a partial fix for the API side. Python side CPython sill exposes a LOT of implementation details, and as a result occasionally projects will choose to rely on some of these details. Then other implementations need to decide whether to also pick the same implementations details and expose them, or use different details, and lack compatibility with any library that depended upon them.

    The python documentation has historically also not been especially clear at distinguishing between what the language guarantees, vs what is just implementation details of the cPython implementation. So even if libraries wanted to try to avoid depending on implementation specifics, it isn't always clear what those are.

    The net result is that for the end user python the language is effectively: whatever cpython does. This really, really discourages creating alternate implementations, as the only way to be an alternative implementation with good compatibility is to be a living fork of cpython, constantly merging in all the changes from it, while also maintaining your improvements.

  42. 42. mohamedkoubaa||context
    This is also slowly being addressed
  43. 43. seabrookmx||context
    That question is already answered. pypy only supports 3.11 today and is largely unmaintained.
  44. 44. t43562||context
    https://pypy.org/posts/2026/10/pypy-v801-release.html

    Last release on Oct 14. Beta support for 3.12. It's not that bad really and 1/10 of the people who complain about it did something then the situation would be better.

  45. 45. jodrellblank||context
    They weren't rebuilding the whole language.

    https://peps.python.org/pep-3000/ - PEP 3000 says it will be a derived from the Python 2 codebase and not a complete rewrite (referencing Joel Spolsky's views on complete rewrites and Netscape Navigator).

    https://peps.python.org/pep-3099/ - PEP 3099 is changes Guido van Rossum rejected from Python 3 (including := as a binding operator), parallel iteration, programmable syntax, parser going beyond LL(1), changing the for/else construct.

    https://peps.python.org/pep-3100/ - PEP 3100 is things he set as goals for it, things like all strings are Unicode and byte arrays are a separate type, optional type annotations, 'exec' and 'print' change from statements to functions, None/True/False become keywords, old-style classes are gone, changing inequality comparison from <> to != , require C99, drop BeOS support, drop old standard library modules, and more.

    actually, more changes than I remember.

  46. 46. adrian17||context
    > It's from converting hashtable lookups into constant-time guard + offset lookups.

    Python already does it in a lot of cases, see opcode specializations like LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_SLOT.

  47. 47. kannanvijayan||context
    I haven't kept up with python development lately, so thanks for pointing that out. I looked this up and it does seem like some sort of property access is being optimized. What's not clear is what the hidden runtime type model is being used for this, or if it's a lightweight tracking that captures some subset of property accesses.

    More digging led to this: https://peps.python.org/pep-0659/ which seems to be what the effort is organized around?

    Python's object semantics are broadly similar to Javascript, bar the prototypical inheritance chain, but with the extra complexity of potentially needing to handle dynamic `__*attr__` overrides. Optimizing for this would require a tree of hidden map objects much like JS JIT engines use. I dug around the codebase a while back looking for something like that but didn't find it. `OrderedDict` seemed promising but after more investigation that turned out to just be adding property ordering to dictionaries.

    The thing is, you can build that entire hidden type structure out, AND optimize against it, without ever having to mess with things like bytecode replacement. Once you have the hidden type model, you can modify the property lookup algorithm in the VM itself (as in cpython c code) to use some annotation structure hanging off of the bytecode to look up inline caches of type-guarded fastpaths. It would be an optimized fastpath that integrated directly into the C code that interprets the GETATTR opcode.

  48. 48. adrian17||context
    > Optimizing for this would require a tree of hidden map objects much like JS JIT engines use.

    I don’t really think that’s true or even that relevant , at least in context of classes (especially with slots - the class, by definition, _is_ the “hidden map”) and not generic dicts.

    > The thing is, you can build that entire hidden type structure out, AND optimize against it, without ever having to mess with things like bytecode replacement.

    Pretty sure the motivation was exactly the opposite - that a simple “if a LOAD_ATTR encounters the same class with slots N times in a row, swap it out for LOAD_ATTR_SLOT with inline cached slot index, and swap back to generic one if something changes” is way easier (both to implement and reason about) than any alternative that’d interact with the object model. (Also it means you skip having to branch between a slow and fast path at all)

    > you can modify the property lookup algorithm in the VM itself (as in cpython c code) to use some annotation structure hanging off of the bytecode to look up inline caches of type-guarded fastpaths. It would be an optimized fastpath that integrated directly into the C code that interprets the GETATTR opcode.

    Sorry, that sounds a bit vague and not too different from what CPython already is doing.

  49. 49. kannanvijayan||context
    Ah, the `__slots__` feature makes it make a lot more sense.

    > Sorry, that sounds a bit vague and not too different from what CPython already is doing.

    With slots being available, I can see where I was misled. I went looking for a type structure that modeled the dynamic properties on an object which would be used as a typeguard, but the class itself functions as that if you're restricting the optimization to slotted properties.

    Appreciate the clarfication!

  50. 50. adrian17||context
    (Note that this optimization can also trigger for plain classes (that’s LOAD_ATTR_INSTANCE_VALUE), it just needs a bit more guards and is only useful if you don’t abuse instances being dynamic objects. I just used slots as the most obvious example, but there are lots of different op specializations since like 3.11)
  51. 51. kzrdude||context
    And we note that these specializations are part of production Python and will not be removed when the JIT is removed.
  52. 52. kannanvijayan||context
    This has been very informative. With object property/method lookup optimized the next big leap in JIT-style perf is actually a hard pull. The next big perf win lies behind local type inference, and a method-jit with your standard bevy of SSA optimizations to hoist the typeguards.

    I suppose the various JIT projects are trying to come at that from different angles incrementally, but that's a genuinely hard problem as you don't see real benefits until multiple complex pieces of infrastructure are in place and with good coverage over the language.

    Anyway, my hot take was misplaced.

  53. 53. graemep||context
    If you look at the reasons for this it seems like a good decision: https://discuss.python.org/t/pep-836-jit-go-brrr-the-path-to...

    There are already many way of addressing Python performance (leaving aside whether Python is a good choice if performance matters) such as Cython, Numba, Pypy and C extensions.

  54. 54. coldtea||context
    >There are already many way of addressing Python performance (leaving aside whether Python is a good choice if performance matters) such as Cython, Numba, Pypy and C extensions.

    And all of them are lacking in different ways, we ALSO, want faster pure Python.

  55. 55. graemep||context
    They all have drawbacks, but they also reduce the case for needing to speed up CPython.

    Pypy does provide faster pure Python. Its a compatible implementation with JIT.

  56. 56. v3ss0n||context
    Onlything is a lot of cextensions are super slow there. that is only bottleneck left which could be solved with resources that those guys spent on experimental jit.
  57. 57. thayne||context
    The newest version of python that PyPy supports is 3.12. CPython is on 3.15.

    And from what I understand there are limitations with using libraries that use the CPython API to interface with native code.

  58. 58. cpburns2009||context
    The problem with PyPy, which I'm a huge fan of BTW, is it's on life-support. The only reason the past couple major versions were released was due to a few small companies or individuals directly implementing the updates themselves. That's my understanding at least. It's disheartening because I've been primarily using PyPy for 5 years, advocated for it, and was looking into contributing more to it before finding out about its state.
  59. 59. t43562||context
    Perhaps if the money which was spent on the built-in JIT had been spent on PyPy we'd be somewhere.

    PyPy wasn't great for me because its startup time interfered with the main usecase I wanted it for in one instance and in another there bugs that made it not quite compatible enough. Money could solve the bug issue.

    On the other hand I did get pygame working with it at one point and that seemed like a nice scenario.

  60. 60. cpburns2009||context
    What would have been really nice is if the $1M/y in funding the PSF rejected due to ideological purity could have been reallocated to PyPy.
  61. 61. xgk||context
    PyPy's problem with slow startup is, in principle, easily fixable.

    When it was created, PyPy did not seek to optimise startup performance. Instead, its aim was steady-state performance of JITed code, and it succeeded handsomely. A conceptually simple fix would be to optimise traces in one processor core, while the interpreter runs in another. Once when the trace is finalised, does interpretation stop and switch to native execution. But PyPy is currently a sequential system and making it parallel, while conceptually easy, is a lot of work and needs a rewrite of the whole system. But, for better or worse, the PyPy team does not have the resources to do this.

    The other of PyPy's big performance issues (Python code using a lot of FFI calls via a suboptimal FFI) is also, in principle, easily fixable. But this is a social problem: the Python community would have to move towards better FFIs.

    In principle, it would also be easy to fix PyPy's resource problem. I am not sure about the social problem ...

  62. 62. t43562||context
    At least CPython could agree to fix its FFI so that PyPy and others would have a chance.
  63. 63. pbronez||context
    Interesting, makes sense. JIT in CPython main is a big deal, glad they’re proceeding with caution. Overall looks like they added it as an experimental feature for two years, then decided to back it out. Perfectly reasonable outcome.
  64. 64. samus||context
    It looks like it very much should never have happened like this. The actually hard and awkward questions have not been asked beforehand, and the SC doesn't like their hands being forced, and rightly so.
  65. 65. anthk||context
    The Rust based Python3 port can keep it and it can still be far more secure than CPython. Not everything it's JIT'ted on RustPython, it's ondemand per function, you have to enable it explicitly.
  66. 66. adrian17||context
    Unfortunate. I've been following the work on it occasionally.

    On one hand, it seemed like JIT work was really progressing in high gear until SC requested a new PEP. Also unfortunate, as it seemed like part of the hope for the JIT was that it'd counter the performance penalty from free threading.

    On the other, it did feel (to me) like with all the fancy (and definitely cool) optimizations it got (automatic refcount operation removal, new type-based specializations, inplace math operations), the macrobenchmark benefits weren't _that_ exciting for a JIT. It definitely has potential for more, maybe with even fancier optimizations like unboxing ints, but the complexity just keeps going up.

    > It said that the PEP was "overly optimistic" about user-visible differences with the JIT enabled.

    The JIT is technically generated from the same source as the interpreter loop itself, so originally the differences were extremely unlikely, but I imagine the risk just kept going up as new JIT-only paths and optimizations were introduced.

    And politically, I feel like SC’s reasoning was just “this side project has landed in main branch almost by accident and has been stewing without oversight ever since, with no stabilization in sight”; and the latest PEP was probably still too vague, with a lot of “here’s more things we can add to the stew” - so I can understand if SC wasn’t satisfied.

  67. 67. cogman10||context
    I think this is a major issue with requiring a PEP for what's a performance optimization.

    JITs are big nasty things that by their nature have to do a lot of things. You are basically saying "Give us a PEP for a new python interpreter and compiler".

    What they do is fuzzy by their nature because optimizations are very rarely universally beneficial. It's a game of measuring, looking for regressions, and tackling the biggest problem next for whatever sample applications you have available. You always run into the risk of overfitting on top of all that (You may have made django faster, but you've made flask slower).

    This is the sort of thing that, IMO, should not go through the PEP process. It's an implementation detail for the runtime.

    Imagine, for example, if the JVM needed a bunch of JEPs for JIT improvements. They'd never get done. Or if any javascript engine needed ECMA acceptance before they could do a new JIT optimization.

  68. 68. adrian17||context
    > Imagine, for example, if the JVM needed a bunch of JEPs for JIT improvements.

    FWIW, I definitely can find a bunch of both PEPs and JEPs for internal optimizations, random examples:

    https://peps.python.org/pep-0509/

    https://openjdk.org/jeps/147

  69. 69. cogman10||context
    You can find those JEPs, but frankly they are there for 1 of 2 reasons.

    1. An outsider to the regular OpenJDK dev team proposing an optimization.

    2. Advertising for a cool new performance tweak with potentially large impact.

    You'll also notice that the JEP descriptions are very different from PEP descriptions.

    Probably the largest JEP for the JVM, Valhalla

    https://openjdk.org/jeps/401

    Does not have the same level of requirements being asked of the Python JIT. Further, it's well understood that this JEP will "live on main" for quite some time in preview before it's accepted and merged.

    What the JEP does, instead, is simply describe the feature and potential risks.

    The vast majority of JVM optimizations do not get a JEP.

  70. 70. adrian17||context
    Fair, I don’t argue with that, I’m not knowledgeable about Java’s processes. Just one thing:

    > The vast majority of JVM optimizations do not get a JEP.

    In Python too. Still, the JIT really is just a really big thing. I don’t know if there could be a better way to do it, as either 1. You develop it off-branch and… make an enormous PR when you’re done, with risks of getting rejected anyway? Or 2, you allow more experiments on main like Rust, but then you end up with hundreds of minor half-maintained nightly-only features, possibly conflicting with each other, and eventually go through bureaucracy to remove them anyway.

  71. 71. cogman10||context
    So, I'd grant that it'd probably be a JEP for java (the initial JIT) but not that every change to the JIT would result in a new JEP. Java's JIT, hotspot, was integrated right before they started the JEP process. The JEP for the JIT would likely be pretty boring like "It's a JIT, it does this, in some applications we see this sort of speed up". Much like the AOT JEP https://openjdk.org/jeps/514

    The Java governance allows for a lot more open ended projects with follow ups. Not that it's reckless, Valhalla is proof of that, but rather that once something is good enough they are pretty open to just shipping it as a preview feature and refining until it is worthy of being stable.

    That's why, for example, we saw ZGC get merged, and then JDK after JDK seeing continuing development and improvement on ZGC (Or G1 for that matter). These GCs were fairly rough on their first release and now they are pretty much best in class.

    I see a Python JIT as the same thing. Delivering the infrastructure for a JIT would need a PIP, but I wouldn't put in things like "acceptance criteria" beyond "doesn't break older code". I would expect such a project to get continual updates without PEPs.

  72. 72. adrian17||context
    > I would expect such a project to get continual updates without PEPs.

    Just for completeness: the original JIT PR was merged quite enthusiastically and only after the fact it was pointed out that it should have went through a PEP process [1]. The following PEP 744 was of the “informational” type, and the just-withdrawn PEP 836 was the first “standards track” PEP, which means that (in my understanding) it’s technically the first actual PEP that the SC would formally comment on. So in a way it’s not “can we update the JIT” PEP, but the first real “does SC want this JIT as proposed” PEP.

    That said, I do agree with most of what you said, especially the acceptance criteria part.

    The issue I have and find it hard to resolve is that since the code was already on main, the feature was already in “sunk cost” mode. It’s hard when the code is already on main and another 3 optimization PRs are always there behind the corner, but it needs to be possible for SC to say “we decided it’s not actually worth all this complexity for <some small number>% speed improvement” (I’m not commenting whether in this particular case it’d have been a right call), and the PEP (if not withdrawn) was the way to exercise that control.

    [1] https://github.com/python/cpython/pull/113465#issuecomment-1...

  73. 73. pjmlp||context
    The original JIT certainly did not get a JEP, because JEPs replaced the previous JSR process.

    And even then, Hotspot did not got a JSR, because all that work was done before Sun started collaborating with industry partners for Java evolution.

    They "simply" ported the JIT compiler from the Strongtalk acquisition into Java.

  74. 74. stickfigure||context
    > Imagine, for example, if the JVM needed a bunch of JEPs for JIT improvements.

    They do:

    https://openjdk.org/jeps/197

    https://openjdk.org/jeps/515

    Not every optimization requires a JEP, but certainly something as big as "add or remove a JIT" would 100% require a JEP.

  75. 75. crabbone||context
    Oh, it's not just a performance optimization. But you've said it yourself: "a new python interpreter and compiler". A lot of Python code out there lives with assumptions of CPython interpreter built into it. Pretty sure pytest would've been affected, should JIT replace the existing interpreter, for example.

    Anyways. I don't believe that Python needs a JIT compiler. I don't believe that CPython can realistically replace its interpreter with JIT compiler without causing major problems with the community packages.

    The way I see it: Python users today desperately want Java. They want it called Python because there's some vague memory still around of Python being cool and Java not being cool.

    In Russian there's a children tale about a hungry soldier returning from a war and a greedy old woman who offered him a bed for the night. The old woman then pretends to have no food for dinner, and a soldier promises her a magic trick of making a porridge out of a hatchet. And so he tells the woman to put a pot on a stove with a hatchet in it, and step by step he makes her add all the ingredients necessary to make a porridge to the pot. The story gave birth to the idiom "hatchet porridge", which is used to describe anything that was created in a similar way: by deception, when another goal was allegedly being pursued.

    So, to me, the current state of Python is this "hatchet porridge". None of its users want the actual Python (the hatchet is still sticking out of the pot), and they keep adding Java ingredients to the pot in hopes to cook up Java. And so was JIT. It just turned out to be too difficult to throw away the hatchet. An the porridge still has some chipped wood in it as well as a metallic taste.

  76. 76. riffraff||context
    Just FYI, basically the same story is common in European folklore, and there's a somewhat idiomatic "stone soup" concept in English

    https://en.wikipedia.org/wiki/Stone_Soup

  77. 77. ActorNightly||context
    I mean, I have had great success with prototyping stuff in python, then letting an llm translate it to C. My 3090 with Gemma4:31b does this very well with a few guidelines.

    Dunno how much investment is needed into language optimization anymore.

  78. 78. mring33621||context
    Agree with the general workflow: prototype with an easy-to-read language then port to lower-level, faster language
  79. 79. 14113||context
    That works well for greenfield code, but if working on compiler optimisations has taught me anything, it's that there is a lot of legacy code out there in the world that would benefit from re-compilation with optimisations - but would be very difficult to re-write for speed (regardless of whether the work is done by a human, AI, or other machine tool). JIT compilation fits very nicely in this niche, as it means that existing Python projects can get (theoretically) better performance without re-writing.
  80. 80. lenerdenator||context
    People have been calling Python a "prototyping" language for decades. I'd be interested to see how many Python projects ever actually get rewritten in a more performant language. My guess is, up until the last five years that was almost never done. Even with LLMs to help, is that the best use of your tokens and humans' time? It doesn't add a feature. It could conceivably cut costs after enough time, but only if done correctly.
  81. 81. nrawe||context
    Doing it currently, Python to Go. Early indications are a 50-98% increase in speed (e.g. one testcase went from 26hrs to 30mins) for network/CPU heavy workload. Conversion via Qwem, lots of testing needed but compute savings will be worth it.
  82. 82. mynegation||context
    Did you mean “50-98% decrease in running time”? Just calculating from your 26hrs to 30 mins seems to imply so. In terms of speed that translates to 100% to 5100% increase in speed.
  83. 83. gf000||context
    Why not go with something like graalpy first? That's much less risk in terms of "we end up slightly changing behavior"
  84. 84. zahlman||context
    > My guess is, up until the last five years that was almost never done.

    Because having just the hot loop in the performant language is often deemed good enough. And there's tons of Python code out there where the "hot loop" is already automatically in C (the various operations implemented in C by the runtime) or where you can get close enough e.g. with Numpy. Consider that things like Pygame can exist; for a lot of the games people want to make, the only thing that really needs to happen anywhere near "bare-metal" speed is blitting.

  85. 85. ActorNightly||context
    > My guess is, up until the last five years that was almost never done.

    It was done plenty. Just with extensions to python like numpy and opencv. There is no reason to translate everything versus just the critical pieces.

  86. 86. grep_it||context
    I've had good success with just using mypyc (https://mypyc.readthedocs.io/en/latest/introduction.html) on typed python code.
  87. 87. nomel||context
    > on typed python code.

    A fairly massive undertaking for existing code, which jit was supposed to be useful for.

  88. 88. zahlman||context
    I would imagine that the LLM has a much easier time adding correct type annotations to old Python code than it does translating it to C.
  89. 89. EdwardDiego||context
    In my experiments with this, maybe, sorta, it'll do some AST stuff then it'll go "dang this shit is dynamic AF" then suggest a static type inference tool, then a runtime type profiler.

    Which honestly, is the right approach.

  90. 90. EdwardDiego||context
    You can use static type analysers and runtime type profilers to add type annotations to a legacy codebase, but the interesting bit would be if you're built on top of a large untyped codebase you don't control like, say, Django, how far it can go.
  91. 91. bjourne||context
    > On the other, it did feel (to me) like with all the fancy (and definitely cool) optimizations it got (automatic refcount operation removal, new type-based specializations, inplace math operations), the macrobenchmark benefits weren't _that_ exciting for a JIT. It definitely has potential for more, maybe with even fancier optimizations like unboxing ints, but the complexity just keeps going up.

    Zero chance of shoehorning that into a standards-compliant Python runtime. Some things are too fundamental to change without affecting the user-visible language: JITting, lazy imports, threading, copying gc, ref counting, etc.

  92. 92. lenkite||context
    I am confused. Why can't they have an experimental, optionally-enabled feature for a few years while they iron out all the issues ? What is wrong with that ? The JDK keeps doing this all the while. They write a new JEP if there are changes across previews.
  93. 93. cedarbyte482||context
    I also dont get it
  94. 94. Krishansubudhi||context
    I hope it does not lead to performance issues later. Python is already famous for being slower than compiled languages.
  95. 95. FranOntanaya||context
    Being slower than a compiled language is not saying much for an interpreted language. But it's slower than PHP which is a closer comparison, and PHP has had JIT for six years now.
  96. 96. pansa2||context
    Ruby has the reputation of being a very slow language, but Python has been slower still since Ruby jumped ahead with version 1.9, almost 20 years ago. Ruby also has had far more success with JIT compilers than Python has.
  97. 97. chao-||context
    >Ruby also has had far more success with JIT compilers than Python has.

    Ruby is on its third (I think?) JIT now? I'm a little surprised, given Ruby's reputation as a wacky "anything goes" language with a very complex grammar, and it makes me wonder why that is? Does it have to do with the design of the runtime itself more than the language semantics? Or is it more incidental, e.g. many popular ibs are C wrappers, already generates bytecode files, and so on.

  98. 98. samus||context
    Getting a JIT right is hard work because time spent by the JIT is time not spent doing actual work, and finding the correct tradeoffs is very much an empirical problem.
  99. 99. byroot||context
    The difference is that Ruby follow the BDFL model, and Ruby's BDFL was willing to allow people to experiment with in-tree development of JITs.

    If the Python steering committee isn't willing to do the same, they'll probably won't get a working JIT any time soon. Developing a JIT externally, or even from a branch, is just too hard.

  100. 100. skeledrew||context
    And PHP is quite the hot mess. Always has been, really. See the security issues over the years, including the most recent for example. Meanwhile I've never seen any serious issues for Python that's triggered mass required fixing. There's something to be said for moving carefully and ensuring things aren't broken to the best of one's ability, which is the SC's purpose.
  101. 101. pjmlp||context
  102. 102. skeledrew||context
    Are you helping me to prove my point? I see 156 results, with 1 in 2023 and the rest before that. Meanwhile there are 801 results with at least a dozen in 2026 for PHP[0], and we still have 2 more months to go.

    [0] https://app.opencve.io/cve/?vendor=php

  103. 103. pjmlp||context
    Hardly, one CVE is enough.
  104. 104. skeledrew||context
    Not at all. I specifically stated "serious issues for Python that's triggered mass required fixing", ie. it was so bad that there were public notices for users to update ASAP. The closest thing I can find is CVE-2022-34265, and that's in Django, not Python itself.
  105. 105. pjmlp||context
    Python is hardly used at PHP scale for Web development.
  106. 106. skeledrew||context
    Agreed. And Python usage is far more diversified. But I fail to see the relevance of usage to a language being stable vs ridden with issues. Well, beyond that one would expect the one being so many things to so many different communities would have more issues than the other used by a single community for a single purpose.
  107. 107. mahboi||context
    and the biggest one, JS
  108. 108. yxhuvud||context
    It is also slower than any other interpreted dynamic language in wide use.
  109. 109. tweakimp||context
    Sad to read this. I had hoped that with the advance of AI capabilities, features like this could be prototyped, tested, implemented and shipped even faster. And I was really looking forward to see performance gains for my favourite language.

    Where do we go from here? Microsoft did not continue to finance the Faster CPython project and the current speed gains are good, but not what we hoped.

  110. 110. Retr0id||context
    At this point if you have a python codebase where perf is an issue, the "AI-pilled" answer is to rewrite it in a faster language.
  111. 111. tweakimp||context
    But I want to continue to understand the code. I dont know Rust (maybe AI can teach me?) and if I let Claude rewrite my current 50k LOC project in Rust, how can I understand what is happening and how can I work on it and think it further?
  112. 112. Yossarrian22||context
    You could try having it rewrite parts of the hot path into Rust with PyO3.
  113. 113. jerf||context
    Rust is not your only option. Nor is it automatically the best option, though it is certainly a solid option for a certain set of requirements. Go is a pretty decent match for a Python rewrite; superficially it seems like you're giving up a lot but under the hood they're philosophically more compatible than meets the eye in a lot of ways. But any static language that you have some other local reasons to prefer is going to blow its socks off in terms of performance. And "blow its socks off" is just for the naive translation of a conventional Python code base over to a new language. If your codebase is amenable to threading and can take advantage of multiple CPUs somehow, the result may blow Python's socks off twice over.

    The problem is that Python just isn't going to go fast. There are some languages that may have had more resources poured into them to make them go faster in absolute terms, like perhaps Java. But I don't think there's a single language that has had so many ways of trying to make it go faster given so much effort over so many decades. It's really time to call it... if you have Python code and it's a performance problem, if one of the many many many different solutions aren't adequate for some reason, Python is not going to get any faster than it is today and you're going to have to move off of it.

    If you need high performance code, Python is simply not the right answer and you're going to have to skill up. Or accept what you have, which you'll have to decide if that's a viable option. If it's fast enough I don't advocate switching casually. But if it isn't, there isn't a realistic prospect that you're going to wake up in a year or two to a 30x-faster Python. I wasn't terribly convinced by that claim back in the early 2000s, but it hadn't really been tested yet. It has been tested now.

  114. 114. anthk||context
    RustPython it's pretty mature.
  115. 115. skeledrew||context
    Not at all.

    > RustPython is in development, and while the interpreter certainly can be used in interesting use cases like running Python in WASM and embedding into a Rust project, do note that RustPython is not totally production-ready.

    - https://github.com/RustPython/RustPython

  116. 116. anthk||context
    I've seen worse reimplementations. For what it does it's pretty close.
  117. 117. LtWorf||context
    Pypy is really fast. Have you tried it?
  118. 118. jerf||context
    First, "if one of the many many many different solutions aren't adequate for some reason" was there for a reason.

    Second, no, it isn't. Pypy is really fast compared to Python. "Compared to Python" is just about the lowest bar there is, though. In absolute terms it is still only a medium-fast language runtime, and it comes with a lot of costs and tradeoffs.

    That's the problem with Python. Lots of ways to take a very slow language and make it a medium-fast language with substantial tradeoffs, or make it a fast language with enormous tradeoffs. If you can handle the tradeoffs, fine. But if you can't you just need to switch to a language that is fast without anywhere near as many tradeoffs.

  119. 119. skeledrew||context
    There are already many solutions to the performance issue from which you can pick. You don't need to understand the C in numpy to use it for example. And I'd say it's highly unlikely that you have a use case that, if it's applicable, isn't already addressed. Like it's generally pointless to optimize language performance for code that's doing a lot of network operations, because network lag will always dwarf such optimizations.
  120. 120. mahboi||context
    There's so much Python code that uses numpy etc but still ends up having some hot part in Python that's nontrivial to translate to something faster. Same reason people get frustrated with the GIL.