[HN Gopher] Free-threaded CPython is ready to experiment with
___________________________________________________________________
Free-threaded CPython is ready to experiment with
Author : ngoldbaum
Score : 188 points
Date : 2024-07-12 19:52 UTC (3 hours ago)
(HTM) web link (labs.quansight.org)
(TXT) w3m dump (labs.quansight.org)
| nas wrote:
| Very encouraging news!
| OutOfHere wrote:
| It has been ready for a few months now, at least since 3.13.0
| beta 1 which released on 2024-05-08, although alpha versions had
| it working too. I don't know why this is news _now_.
|
| With it, the single-threaded case is slower.
| TylerE wrote:
| FTA: "Yesterday, py-free-threading.github.io launched! It's
| both a resource with documentation around adding support for
| free-threaded Python, and a status tracker for the rollout
| across open source projects in the Python ecosystem."
| OutOfHere wrote:
| Before the article came the misleading title: "Free-threaded
| CPython is ready to experiment with".
|
| The link should have been to https://py-free-
| threading.github.io/tracking/
| JBorrow wrote:
| This release coincides with the SciPy 2024 conference and a
| number of other things. I would suggest reading the article to
| learn more.
| OutOfHere wrote:
| > This release
|
| What release. The last release of CPython was 3.13.0b3 on
| 2024-06-27.
|
| SciPy is irrelevant to the title.
| nine_k wrote:
| Python 3 progress so far: [x] Async. [x]
| Optional static typing. [x] Threading. [ ] JIT.
| [ ] Efficient dependency management.
| janice1999 wrote:
| Not sure what this list means, there are successful languages
| without these feature. Also Python 3.13 [1] has an optional JIT
| [2], disabled by default.
|
| [1] https://docs.python.org/3.13/whatsnew/3.13.html
|
| [2] https://peps.python.org/pep-0744/
| jolux wrote:
| The successful languages without efficient dependency
| management are painful to manage dependencies in, though. I
| think Python should be shooting for a better package
| management user experience than C++.
| yosefk wrote:
| If Python's dependency management is better than anything,
| it's better than C++'s. Python has pip and venv. C++ has
| nothing (you could say less than nothing since you also
| have ample opportunity for inconsistent build due to
| mismatching #defines as well as using the wrong binaries
| for your .h files and nothing remotely like type-safe
| linkage to mitigate human error. It also has an infinite
| number of build systems where each system of makefiles or
| cmakefiles is its own build system with its own conventions
| and features). In fact python is the best dependency
| management system for C++ code when you can get binaries
| build from C++ via pip install...
| wiseowise wrote:
| > If Python's dependency management is better than
| anything, it's better than C++'s.
|
| That's like the lowest possible bar to clear.
| Galanwe wrote:
| Not sure this is still a valid critic of Python in 2024.
|
| Between pip, poetry and pyproject.toml, things are now
| quite good IMHO.
| Arcanum-XIII wrote:
| All is well, then, one day, you have to update one
| library.
|
| Some days later, in some woods or cave, people will hear
| your screams of rage and despair.
| Galanwe wrote:
| Been using python for 15 years now, and these screams
| were never heard.
|
| Dev/test with relaxed pip installs, freeze deployment
| dependencies with pip freeze/pip-
| tools/poetry/whateveryoulike, and what's the problem?
| neeleshs wrote:
| same here. Been using python/pip for 10+ years and this
| was never a problem. In the java world, there is jar
| hell, but it was never a crippling issue, but a minor
| annoyance once a year or so.
|
| In general, is dependency management such a massive
| problem it is made to be on HN? Maybe people here are
| doing far more complex/different things than I've done in
| the past 20 years
| arp242 wrote:
| I guess that depends from your perspective. I'm not a
| Python developer, but like many people I do want to run
| Python programs from time to time.
|
| I don't really know Rust, or Cargo, but I never have
| trouble building any Rust program: "cargo build
| [--release]" is all I need to know. Easy. Even many C
| programs are actually quite easy: "./configure", "make",
| and optionally "make install". "./configure" has a nice "
| --help". There is a lot to be said about the ugly
| generated autotools soup, but the UX for people just
| wanting to build/run it without in-depth knowledge of the
| system is actually quite decent. cmake is a regression
| here.
|
| With Python, "pip install" gives me an entire screen full
| of errors about venv and "externally managed" and
| whatnot. I don't care. I just want to run it. I don't
| want a bunch of venvs, I just want to install or run the
| damn program. I've taken to just use "pip install
| --break-system-packages", which installs to ~/.local. It
| works _shrug_.
|
| Last time I wanted to just run a project with a few small
| modifications I had a hard time. I ended up just editing
| ~/.local/lib/python/[...] Again, it worked so whatever.
|
| All of this is really where Python and some other
| languages/build systems fail. Many people running this
| are not $language_x programmers or experts, and I don't
| want to read up on every system I come across. That's not
| a reasonable demand.
|
| Any system that doesn't allow non-users of that language
| to use it in simple easy steps needs work. Python's
| system is one such system.
| simonw wrote:
| "I don't want a bunch of venvs"
|
| That's your problem right there.
|
| Virtual environments are the Python ecosystem's solution
| to the problem of wanting to install different things on
| the same machine that have different conflicting
| requirements.
|
| If you refuse to use virtual environments and you install
| more than one separate Python project you're going to run
| into conflicting requirements and it's going to suck.
|
| Have you tried pipx? If you're just installing Python
| tools (and not hacking on them yourself) it's fantastic -
| it manages separate virtual environments for each of your
| installations without you having to think about them (or
| even know what a virtual environment is).
| arp242 wrote:
| Managing a farm of virtualenvs and mucking about with my
| PATH doesn't address the user-installable problem at all.
| est wrote:
| Deps in CPython are more about .so/.dll problem, not much
| can be done since stuff happens outside python itself.
| GTP wrote:
| I don't get how this optional static typing works. I had a
| quick look at [1], and it begins with a note saying that
| Python's runtime doesn't enforce types, leaving the impression
| that you need to use third-party tools to do actual type
| checking. But then it continues just like Python does the
| check. Consider that I'm not a Python programmer, but the main
| reason I stay away from it is the lack of a proper type system.
| If this is going to change, I might reconsider it.
|
| [1] https://docs.python.org/3/library/typing.html
| wk_end wrote:
| The interpreter does not and probably never will check types.
| The annotations are treated as effectively meaningless at
| runtime. External tools like mypy can be run over your code
| and check them.
| davepeck wrote:
| Third party tools (mypy, pyright, etc) are expected to check
| types. cpython itself does not. This will run just fine:
|
| python -c "x: int = 'not_an_int'"
|
| My opinion is that with PEP 695 landing in Python 3.12, the
| type system itself is starting to feel robust.
|
| These days, the python ecosystem's key packages all tend to
| have extensive type hints.
|
| The type checkers are of varying quality; my experience is
| that pyright is fast and correct, while mypy (not having the
| backing of a Microsoft) is slower and lags on features a
| little bit -- for instance, mypy still hasn't finalized
| support for PEP 695 syntax.
| zitterbewegung wrote:
| Optional static typing is just like a comment (real term is
| annotation) of the input variable(s) and return variable(s).
| No optimization is performed. Using a tool such as mypy that
| kicks off on a CI/CD process technically enforces types but
| they are ignored by the interpreter unless you make a syntax
| error.
| nine_k wrote:
| A language server in your IDE kicks in much earlier, and is
| even more helpful.
| sveiss wrote:
| The parser supports the type hint syntax, and the standard
| library provides various type hint related objects.
|
| So you can do things like "from typing import Optional" to
| bring Optional into scope, and then annotate a function with
| -> Optional[int] to indicate it returns None or an int.
|
| Unlike a system using special comments for type hints, the
| interpreter will complain if you make a typo in the word
| Optional or don't bring it into scope.
|
| But the interpreter doesn't do anything else; if you actually
| return a string from that annotated function it won't
| complain.
|
| You need an external third party tool like MyPy or Pyre to
| consume the hint information and produce warnings.
|
| In practice it's quite usable, so long as you have CI
| enforcing the type system. You can gradually add types to an
| existing code base, and IDEs can use the hint information to
| support code navigation and error highlighting.
| nine_k wrote:
| At MPOW most Python code is well-type-hinted, and mypy and
| pyright are very helpful at finding issues, and also for
| stuff like code completion and navigation, e.g. "go to the
| definition of the type of this variable".
|
| Works pretty efficiently.
|
| BTW, Typescript also does not enforce types at runtime. Heck,
| C++ does not enforce types at runtime either. It does not
| mean that their static typing systems don't help during at
| development time.
| GTP wrote:
| > BTW, Typescript also does not enforce types at runtime.
| Heck, C++ does not enforce types at runtime either. It does
| not mean that their static typing systems don't help during
| at development time.
|
| Speaking of C here as I don't have web development
| experience. The static type system does help, but in this
| case, it's the compiler doing the check at compile time to
| spare you many surprises at runtime. And it's part of the
| language's standard. Python itself doesn't do that. Good
| that you can use external tools, but I would prefer if this
| was part of Python's spec.
|
| Edit: these days I'm thinking of having a look at Mojo, it
| seems to do what I would like from Python.
| VeejayRampay wrote:
| python will never be "properly typed"
|
| what it has is "type hints" which is way to have richer
| integration with type checkers and your IDE, but will never
| offer more than that as is
| hot_gril wrote:
| It is properly typed: it has dynamic types :)
| GTP wrote:
| Then we have very different ideas of what proper typing
| is :D Look at this function, can you tell me what it
| does? def plus(x, y): return x+y
|
| If your answer is among the lines of "It returns the sum
| x and y" then I would ask you who said that x and y are
| numbers. If these are strings, it concatenates them. If
| instead you pass a string and a number, you will get a
| runtime exception. So not only you can't tell what a
| function does just by looking at it, you can't even know
| if the function is correct (in the sense that will not
| raise an exception).
| hot_gril wrote:
| When is the last time you had a bug IRL caused by passing
| the wrong kind of thing into plus(x, y), which your tests
| didn't catch?
| andrewaylett wrote:
| It calls x.__add__(y).
|
| Python types are strictly specified, but also dynamic.
| You don't need _static_ types in order to have _strict_
| types, and indeed just because you 've got static types
| (in TS, for example) doesn't mean you have strict types.
|
| A Python string is always a string, nothing is going to
| magically turn it into a number just because it's a
| string representation of a number. The same (sadly) can't
| be said of Javascript.
| nequo wrote:
| Both Haskell and OCaml can raise exceptions for you, yet
| most people would say that they are properly typed.
|
| The plus function you wrote is not more confusing than
| any generic function in a language that supports that.
| hot_gril wrote:
| I think static typing is a waste of time, but given that you
| want it, I can see why you wouldn't want to use Python. Its
| type-checking is more half-baked and cumbersome than other
| languages, even TS.
| baq wrote:
| Typescript is pretty much the gold standard, it's amazing
| how much JavaScript madness you can work around just on the
| typechecking level.
|
| IMHO Python should shamelessly steal as much typescript's
| typing as possible. It's tough since the Microsoft
| typescript team is apparently amazing at what they do so
| for now it's a very fast moving target but some day...
| hot_gril wrote:
| Well the TS tooling is more painful in ways. It's not
| compatible with some stuff like the NodeJS profiler. Also
| there's some mess around modules vs "require" syntax that
| I don't understand fully but TS somehow plays a role.
| GTP wrote:
| I instead think that the lack of static typing is a waste
| of time, since without it you can have programs that waste
| hours of computation due to an exception that would have
| been prevented by a proper type system ;)
| nine_k wrote:
| I used to think like that until I tried.
|
| There are areas where typing is more important: public
| interfaces. You don't have to make every piece of your
| program well-typed. But signatures of your public functions
| / methods matter a lot, and from them types of many
| internal things can be inferred.
|
| If your code has a well-typed interface, it's pleasant to
| work with. If interfaces of the libraries you use are well-
| typed, you have easier time writing your code (that
| interacts with them). Eventually you type more and more
| code you write and alter, and keep reaping the benefits.
| hot_gril wrote:
| I shouldn't have said it's a waste of time period, cause
| every project I work on _does_ have static typing in two
| very important places: the RPC or web API (OpenAPI, gRPC,
| whatever it is), and the relational database. But not in
| the main JS or Py code. That 's all I've ever needed.
|
| I did try migrating a NodeJS backend to TS along with a
| teammate driving that effort. We caught absolutely 0
| additional bugs with the new type-checking in place, and
| the extra time we spent on that stuff could've gone into
| better testing instead. So it actually made things more
| dangerous.
| simonw wrote:
| This was the thing that started to bring me around to
| optional typing as well. It makes the most sense to me as
| a form of documentation - it's really useful to know what
| types are expected (and returned) by a Python function!
|
| If that's baked into the code itself, your text editor
| can show inline information - which saves you from having
| to go and look at the documentation yourself.
|
| I've started trying to add types to my libraries that
| expose a public API now. I think it's worth the extra
| effort just for the documentation benefit it provides.
| alfalfasprout wrote:
| The conda-forge ecosystem is making big strides in dependency
| management. No more are we stuck with the abysmal pip+venv
| story.
| ramses0 wrote:
| You forgot: [X] print requires parentheses
| VeejayRampay wrote:
| the efficient dependency management is coming, the good people
| of astral will take care of that with the uv-backed version of
| rye (initially created by Armin Ronacher with inspirations from
| Cargo), I'm really confident it'll be good like ruff and uv
| were good
| agumonkey wrote:
| I'm eager to see what a simple JIT can bring to computing
| energy savings on python apps.
| eigenvalue wrote:
| Really excited for this. Once some more time goes by and the most
| important python libraries update to support no GIL, there is
| just a tremendous amount of performance that can be automatically
| unlocked with almost no incremental effort for so many
| organizations and projects. It's also a good opportunity for new
| and more actively maintained projects to take market share from
| older and more established libraries if the older libraries don't
| take making these changes seriously and finish them in a timely
| manner. It's going to be amazing to saturate all the cores on a
| big machine using simple threads instead of dealing with the
| massive overhead and complexity and bugs of using something like
| multiprocessing.
| phkahler wrote:
| I feel like most things that will benefit from moving to
| multiple cores for performance should probably not be written
| in Python. OTH "most" is not "all" so it's gonna be awesome for
| some.
| MBCook wrote:
| But it would give you more headroom before rewriting for
| performance would make sense right? That alone could be
| beneficial to a lot of people.
| DanielVZ wrote:
| Usually performance critical code is written in cpp, fortran,
| etc, and then wrapped in libraries for Python. Python still
| has a use case for glue code.
| mihaic wrote:
| Does anyone know if there is more serious single threaded
| performance degradation (more than a few percent for instance)? I
| couldn't find any benchmarks, just some generic reassurance that
| everything is fine.
| ngoldbaum wrote:
| Right now there is a significant single-threaded performance
| cost. Somewhere from 30-50%. Part of what my colleague Ken Jin
| and others are working on is getting back some of that lost
| performance by applying some optimizations. Expect single-
| threaded performance to improve for Python 3.14 next year.
| arp242 wrote:
| To be honest, that seems a lot. Even today a lot of code is
| single-threaded, and this performance hit will also affect a
| lot of code running in parallel today.
|
| There have been patches to remove the GIL going back to the
| 90s and Python 1.5 or thereabouts. But the performance impact
| has always been the show-stopper.
| ngoldbaum wrote:
| It's an experimental release in 3.13, definitely no where
| near final. Another example: objects that will have
| deffered reference counts in 3.14 are made immortal in 3.13
| to avoid scaling issues from reference count thrashing.
| This wasn't originally the plan but deferred reference
| counting didn't land in time for 3.13. It will be several
| years before free-threading becomes the default, at that
| point there will no longer be any single-threaded
| performance drop. Of course that assumes everything shakes
| out as planned, we'll see.
| deschutes wrote:
| To my understanding there is and there isn't. The driving force
| behind this demonstrated that it was possible to speed up the
| existing CPython interpreter by more than the performance cost
| of free threading with changes to the allocator and various
| other things.
|
| So the net is actually a small performance win but lesser than
| if there was no free threading. That said, many of the
| techniques he identified were immediately incorporated into
| CPython and so I would expect benchmarks to show some
| regression as compared with the single threaded interpreter of
| the previous revision.
| Sparkyte wrote:
| My body is ready. I love python because the ease of writing and
| logic. Hopefully the more complicated free-threaded approach is
| comprehensive enough to write it like we traditionally write
| python. Not saying it is or isn't I just haven't dived enough
| into python multithreading because it is hard to put those demons
| back once you pull them out.
| ZhongXina wrote:
| Precisely, ease of _writing_ , not ease of reading (the whole
| project, not just a tiny snippet of code) or supporting it
| long-term.
| ameliaquining wrote:
| The semantic changes are negligible for authors of Python code.
| All the complexity falls on the maintainers of the CPython
| interpreter and on authors of native extension modules.
| stavros wrote:
| Well, I'm not looking forward to the day when I upgrade my
| Python and suddenly I have to debug a ton of fun race
| conditions.
| teaearlgraycold wrote:
| It's kept behind a flag. Hopefully will be forever.
| hot_gril wrote:
| What are the common use cases for threading in Python? I feel
| like that's a lower level tool than most Python projects would
| want, compared to asyncio or multiprocessing.Pool. JS is the
| most comparable thing to Python, and it got pretty darn far
| without threads.
| BugsJustFindMe wrote:
| Working with asyncio sucks when all you want is to be able to
| do some things in the background, possibly concurrently. You
| have to rewrite the worker code using those stupid async
| await keywords. It's an obnoxious constraint that completely
| breaks down when you want to use unaware libraries. The
| thread model is just a million times easier to use because
| you don't have to change the code.
| hot_gril wrote:
| Asyncio is designed for things like webservers or UIs where
| some framework is probably already handling the main event
| loop. What are you doing where you just want to run
| something else in the background, and IPC isn't good
| enough?
| BugsJustFindMe wrote:
| Non-blocking HTTP requests is an extremely common need,
| for instance. Why the hell did we need to reinvent
| special asyncio-aware request libraries for it? It's
| absolute madness. Thread pools are much easier to work
| with.
|
| > _where some framework is probably already handling the
| main event loop_
|
| This is both not really true and also irrelevant. When
| you need a flask (or whatever) request handler to do
| parallel work, asyncio is still pretty bullshit to use vs
| threads.
| hot_gril wrote:
| Non-blocking HTTP request is the bread and butter use
| case for asyncio. Most JS projects are doing something
| like this, and they don't need to manage threads for it.
| You want to manage your own thread pool for this, or are
| you going to spawn and kill a thread every time you make
| a request?
| BugsJustFindMe wrote:
| > _Non-blocking HTTP request is the bread and butter use
| case for asyncio_
|
| And the amount of contorting that has to be done for it
| in Python would be hilarious if it weren't so sad.
|
| > _Most JS projects_
|
| I don't know what JavaScript does, but I do know that
| Python is not JavaScript.
|
| > _You want to manage your own thread pool for this..._
|
| In Python, concurrent futures' ThreadPoolExecutor is
| actually nice to use and doesn't require rewriting
| existing worker code. It's already done, has a clean
| interface, and was part of the standard library before
| asyncio was.
| stavros wrote:
| I feel you. I know asyncio is "the future", but I usually
| just want to write a background task, and really hate all
| the gymnastics I have to do with the color of my
| functions.
| BugsJustFindMe wrote:
| I feel like "asyncio is the future" was invented by the
| same people who think it's totally normal to switch to a
| new javascript web framework every 6 months.
| hot_gril wrote:
| ThreadPoolExecutor is the most similar thing to asyncio:
| It hands out promises, and when you call .result(), it's
| the same as await. JS even made its own promises
| implicitly compatible with async/await. I'm mentioning
| what JS does because you're describing a very common JS
| use case, and Python isn't all that different.
|
| If you have async stuff happening all over the place,
| what do you use, a global ThreadPoolExecutor? It's not
| bad, but a bit more cumbersome and probably less
| efficient. You're running multiple OS threads that are
| locking, vs a single-threaded event loop.
|
| Also, I was originally asking about free threads. GIL
| isn't a problem if you're just waiting on I/O. If you
| want to compute on multiple cores at once, there's
| multiprocessing, or more likely you're using stuff like
| numpy that uses C threads anyway.
| BugsJustFindMe wrote:
| > _Python isn 't all that different_
|
| Again, Python's implementation of asyncio does not allow
| you to background worker code without explicitly altering
| that worker code to be aware of asyncio. Threads do. They
| just don't occupy the same space.
|
| > _there 's multiprocessing_
|
| Eh, the obvious reason to not want to use separate
| processes is a desire for some kind of shared state
| without the cost or burden of IPC.
| kristjansson wrote:
| You don't? concurrent.futures.ThreadPoolExecutor can get
| a lot done without touching async code.
| BugsJustFindMe wrote:
| I am a big advocate for ThreadPoolExecutor. I'm saying
| it's superior to asyncio. The person I'm responding to
| was asking why use threads when you can use asyncio
| instead.
| bongodongobob wrote:
| Same as any other language. Separating UI from calculations
| is my most common need for it.
| vldmrs wrote:
| Great news ! It would be interesting to see performance
| comparison for IO-bound tasks like http requests between single-
| threaded asyncio code and multi-threaded asyncio
| discreteevent wrote:
| I remember back around 2007 all the anxious blog posts about the
| free lunch (Moore's law) being over. Parallelism was mandatory
| now. We were going to need exotic solutions like software
| transactional memory to get out of the crisis (and we could
| certainly forget about object orientation).
|
| Meanwhile what takes the crown? - Single threaded python.
|
| (Well, ok Rust looks like it's taking first place where you
| really need the speed and it does help parallelism without
| requiring absolute purity)
| elijahbenizzy wrote:
| I'm really curious to see how this will work with async. There's
| a natural barrier (I/O versus CPU-bound code), which isn't always
| a perfect distinction.
|
| I'd love to see a more fluid model between the two -- E.G. if I'm
| doing a "gather" on CPU-bound coroutines, I'm curious if there's
| something that can be smart enough to JIT between async and
| multithreaded implementations.
|
| "Oh, the first few tasks were entirely CPU-bound? Cool, let's
| launch another thread. Oh, the first few threads were I/O-bound?
| Cool, let's use in-thread coroutines".
|
| Probably not feasible for a myriad of reasons, but even a more
| fluid programming model could be really cool (similar interfaces
| with a quick swap between?).
| anacrolix wrote:
| Was ready for this 15 years ago when I loved Python and regularly
| contributed. At the time, nobody wanted to do it and I got bored
| and went to Go.
| throwaway5752 wrote:
| GVR, you are sorely missed, though I hope you are enjoying life.
| gnatolf wrote:
| Good to hear. The authors are touching on the journey it is to
| make Cython continue to work. I wonder how hard it'll be to
| continue to provide bdist packages, or within what timeframe, if
| at all, Cython can transparently ensure correctness for a no-gil
| build. Anyone got any insights?
___________________________________________________________________
(page generated 2024-07-12 23:00 UTC)