[HN Gopher] Free-threaded CPython is ready to experiment with
       ___________________________________________________________________
        
       Free-threaded CPython is ready to experiment with
        
       Author : ngoldbaum
       Score  : 462 points
       Date   : 2024-07-12 19:52 UTC (1 days 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.
        
               | yosefk wrote:
               | Agreed, but that was the bar set by the comment I was
               | replying to, which claimed Python doesn't clear it.
        
               | vulnbludog wrote:
               | On bro
        
               | stavros wrote:
               | That was the entire point, that C++ is the absolute
               | worst.
        
               | dgfitz wrote:
               | I pip3 installed something today. It didn't work, at all.
               | 
               | I then yum installed a lib and headers, it worked well.
               | 
               | C++ on an msft platform is the worst. I can't speak for
               | Mac. C++ on a linux is quite pleasant. Feels like most of
               | the comments like yours are biased for un-stated reasons.
        
               | stavros wrote:
               | If I had a penny for every time I gave up on compiling
               | C++ software because there's no way to know what
               | dependencies it needs, I'd be a millionaire. Python at
               | least lists them.
        
               | dgfitz wrote:
               | If I had a penny every time I heard something like that
               | on sites like this, I'd be a billionaire :)
        
               | ahartmetz wrote:
               | Is that because the compiler failed with "foo.h not
               | found" or the build system said "libfoo not found"? CMake
               | is most common and it will tell you. Worst case it's
               | difficult to derive the package name from the name in the
               | diagnostic.
               | 
               | It's not great, but usually not a big deal neither IME.
               | Typically a couple of minutes to e.g. find that required
               | libSDL2 addon module or whatever, if there is that kind
               | of problem at all.
        
               | stavros wrote:
               | Yes it is, and it's usually such a big deal for me that I
               | just don't use that software. I don't have time to go
               | through a loop of "what's the file name? What package is
               | it in? Install, repeat". This is by far the worst
               | experience I've had with any language. Python has been a
               | breeze in comparison.
        
               | dgfitz wrote:
               | I'm not going to refute your points. If you're going to
               | wear rose-tinted glasses about all of the bad parts about
               | python, that's fine, I also like python.
        
               | stavros wrote:
               | What's rose-tinted about "one of them downloads
               | dependencies automatically, the other one doesn't"?
        
               | cozzyd wrote:
               | I mean this is a documentation problem. It's pretty
               | common for python to import something it doesn't say it
               | depends on too, btw...
        
               | yupyupyups wrote:
               | Mac has the Brew project, which is sort of like apt-get
               | or yum.
        
               | viraptor wrote:
               | This has nothing to do with languages. You can yum
               | install python packages and expect them to work fine. You
               | can install C++ files using an actual dependency manager
               | like vcpkg or conan and have issues.
               | 
               | You're pointing out differences between software package
               | management styles, not languages.
        
               | andmkl wrote:
               | C++ has apt-get etc. because the libraries do not change
               | all the time. Also, of course there are vcpkg and conan.
               | 
               | Whenever you try to build something via pip, the build
               | will invariably fail. The times that NumPy built from
               | source from PyPI are long over. In fact, at least 50% of
               | attempted package builds fail.
               | 
               | The alternative of binary wheels is flaky.
        
               | viraptor wrote:
               | > C++ has apt-get
               | 
               | That's not a development dependency manager. System
               | package management is a different kind of issue, even if
               | there's a bit of overlap.
               | 
               | > because the libraries do not change all the time
               | 
               | That's not true in practice. Spend enough time with
               | larger projects or do some software packaging and you'll
               | learn that the pain is everywhere.
        
             | 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
        
               | mixmastamyk wrote:
               | Guessing that folks who write such things are lacking
               | sysad skills like manipulating paths, etc.
               | 
               | It does take Python expertise to fix other issues on
               | occasion but they are fixable. Why I think flags like
               | 'pip --break-system-packages' are silly. It's an
               | optimization for non-users over experienced ones.
        
               | 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.
               | And it seems there's a new tool to try every few months
               | that really will fix all problems this time.
               | 
               | And maybe if you're a Python developer working on the
               | code every day that's all brilliant. But most people
               | aren't Python developers, and I just want to try that
               | "Show HN" project or whatnot.
               | 
               | Give me a single command I can run. Always. For any
               | project. And that always works. If you don't have that
               | then your build system needs work.
        
               | simonw wrote:
               | "Give me a single command I can run. Always. For any
               | project. And that always works."                   pipx
               | install X
        
               | arp242 wrote:
               | Right so; I'll try that next time. Thanks. I just go by
               | the very prominent "pip install X" on every pypi page (as
               | well as "pip install .." in many READMEs).
        
               | simonw wrote:
               | Yeah, totally understand that - pipx is still pretty
               | poorly known by people who are active in Python
               | development!
               | 
               | A few of my READMEs start like this:
               | https://github.com/simonw/paginate-json?tab=readme-ov-
               | file#i...                   ## Installation
               | pip install paginate-json              Or use pipx (link
               | to pipx site)              pipx install paginate-json
               | 
               | But I checked and actually most them still don't even
               | mention it. I'll be fixing that in the future.
        
               | pletnes wrote:
               | Pipx is great! Although, I always seem to have to set up
               | PATH, at least on windows?
        
               | Ringz wrote:
               | That single command is pipx.
        
               | zo1 wrote:
               | I could say the exact same stuff about NodeJs, c++, go,
               | rust, php, etc. All of these are easy to use and debug
               | and "install easily" when you know them and use them
               | regularly, and the opposite if you're new. Doubly-so if
               | you personally don't like that language or have some
               | personal pet peeve about it's choices.
               | 
               | Guys let's not pretend like this is somehow unique to
               | python. It's only until about a few years ago that it was
               | incredibly difficult to install and use npm on windows.
               | Arguably the language ecosystem with the most cumulative
               | hipster-dev hours thrown at it, and it still was a
               | horrible "dev experience".
        
               | guhidalg wrote:
               | Normal users who just want to run some code shouldn't
               | need to learn why they need a venv or any of its
               | alternatives. Normal users just want to download a
               | package and run some code without having to think about
               | interfering with other packages. Many programming
               | languages package managers give them that UX and you
               | can't blame them for expecting that from Python. The
               | added step of having to think about venvs with Python is
               | not good. It is a non-trivial system that every single
               | Python user is forced to learn, understand, and the
               | continually remember every time they switch from one
               | project to another.
        
               | nine_k wrote:
               | This is correct. The whole _application_ installation
               | process, including the creation of a venv, installing
               | stuff into it, and registering it with some on-PATH
               | launcher should be one command.
               | 
               | BTW pyenv comes relatively close.
        
               | simonw wrote:
               | I agree with that. Until we solve that larger problem,
               | people need to learn to use virtual environments, or at
               | least learn to install Python tools using pipx.
        
               | VagabundoP wrote:
               | sudo apt install pipx
               | 
               | pipx install package_name
               | 
               | Takes care of the venv and the script/app path is added
               | to system path.
        
               | kallapy wrote:
               | I reject the virtual environments and have no issues. On
               | an untrusted machine (see e.g. the recent token leak):
               | /a/bin/python3 -m pip install foo       /b/bin/python3 -m
               | pip install bar
               | 
               | The whole venv thing is overblown but a fertile source
               | for blogs and discussions. If C-extensions link to
               | installed libraries in site-packages, of course they
               | should use RPATH.
        
               | imtringued wrote:
               | Pythons venvs are a problem to the solution of solving
               | the dependency problem. Consider the following: it is not
               | possible to relocate venvs. In what universe does this
               | make sense? Consider a C++ or Rust binary that would only
               | run when it is placed in /home/simonw/.
        
               | vhcr wrote:
               | Do you have a problem with Node.js too because it creates
               | a node_modules folder, or is the problem that it is not
               | handled automatically?
        
               | arp242 wrote:
               | I don't care about the internals. I care about "just"
               | being able to run it.
               | 
               | I find that most JS projects work fairly well: "npm
               | install" maybe followed by "npm run build" or the like.
               | This isn't enforced by npm and I don't think npm is
               | perfect here, but practical speaking as a non-JS dev just
               | wanting to run some JS projects: it works fairly well for
               | almost all JS projects I've wanted to run in the last
               | five years or so.
               | 
               | A "run_me.py" that would *Just Work(tm)" is fine. I don't
               | overly care what it does internally as long as it's not
               | hugely slow or depends on anything other than "python".
               | Ideally this should be consistent throughout the
               | ecosystem.
               | 
               | To be honest I can't imagine shipping any project
               | intended to be run by users and not have a simple, fool-
               | proof, and low-effort way of running it by anyone of any
               | skill level, which doesn't depend on any real knowledge
               | of the language.
        
               | sgarland wrote:
               | > To be honest I can't imagine shipping any project
               | intended to be run by users and not have a simple, fool-
               | proof, and low-effort way of running it by anyone of any
               | skill level, which doesn't depend on any real knowledge
               | of the language.
               | 
               | This is how we got GH Issues full of inane comments, and
               | blogs from mediocre devs recommending things they know
               | nothing about.
               | 
               | I see nothing wrong with not catering to the lowest
               | common denominator.
        
               | arp242 wrote:
               | Like people with actual lives to live and useful stuff to
               | do that's not learning about and hand-holding a dozen
               | different half-baked build systems.
               | 
               | But sure, keep up the cynical illusion that everyone is
               | an idiot if that's what you need to go through life.
        
               | sgarland wrote:
               | I didn't say that everyone is an idiot. I implied that
               | gate keeping is useful as a first pass against people who
               | are unlikely to have the drive to keep going when they
               | experience difficulty.
               | 
               | When I was a kid, docs were literally a book. If you
               | asked for help and didn't cite what you had already tried
               | / read, you'd be told to RTFM.
               | 
               | Python has several problems. Its relative import system
               | is deranged, packaging is a mess, and yes, on its face
               | needing to run a parallel copy of the interpreter to pip
               | install something is absurd. I still love it. It's baked
               | into every *nix distro, a REPL is a command away, and its
               | syntax is intuitive.
               | 
               | I maintain that the relative ease of JS - and more
               | powerfully, Node - has created a monstrous ecosystem of
               | poorly written software, with its adherents jumping to
               | the latest shiny every few months because this time, it's
               | different. And I _like_ JS (as a frontend language).
        
               | sgarland wrote:
               | This is mostly a curse of Python's popularity. The reason
               | you can't pip install with system Python is that it can
               | break things, and when your system is relying on Python
               | to run various tools, that can't be allowed. No one
               | (sane) is building OS-level scripts with Node.
               | 
               | The simplest answer, IMO, is to download the Python
               | source code, build it, and then run make altinstall.
               | It'll install in parallel with system Python, and you can
               | then alias the new executable path so you no longer have
               | to think about it. Assuming you already have gcc's tool
               | chain installed, it takes roughly 10-15 minutes to build.
               | Not a big deal.
        
               | Galanwe wrote:
               | Maybe I am biased, because I learned these things so long
               | ago and I don't realize that it's a pain to learn. But
               | what exactly is so confusing about virtualenvs ?
               | 
               | They really not that different from any other packaging
               | system like JS or Rust. The only difference is instead of
               | relying on your current directory to find the the
               | libraries / binaries (and thus requiring you to wrap
               | binaries call with some wrapper to search in a specific
               | path), they rely on you sourcing an `activate` script.
               | That's really just it.
               | 
               | Create a Virtualenv:                   $ virtualenv myenv
               | 
               | Activate it, now it is added to your $PATH:
               | $ . myenv/bin/activate
               | 
               | There really is nothing more in the normal case.
               | 
               | If you don't want to have to remember it, create a global
               | Virtualenv somewhere, source it's activate in your
               | .bashrc, and forget it ever existed.
        
               | imtringued wrote:
               | Only python demands you to source an activation script
               | before doing anything.
        
               | VagabundoP wrote:
               | Its more probable that you are trying to install the deps
               | in the system python. And using pip instal xxxxx -u will
               | install them in your user directory rather than the
               | system. I'm pretty sure modern Ubuntu warns you against
               | doing that now anyway.
               | 
               | If you're installing for a small script then doing python
               | -m venv little_project in you home dir is
               | straightforward, just active it after [1]
               | 
               | I'm using rye[2] now and its very similar to Rust's
               | Cargo, it wraps a bunch of the standard toolchain and
               | manages standalone python versions in the background, so
               | doesn't fall into the trap of linux system python issues.
               | 
               | [1]https://docs.python.org/3/library/venv.html
               | [2]https://rye.astral.sh/
        
               | pletnes wrote:
               | This is the truth right here. The issues are with people
               | using (not officially) deprecated tools and workflows,
               | plus various half baked scripts that solved some narrow
               | use cases.
        
             | est wrote:
             | Deps in CPython are more about .so/.dll problem, not much
             | can be done since stuff happens outside python itself.
        
             | __MatrixMan__ wrote:
             | Python's dependency management sucks because they're
             | audacious enough to attempt packaging non-python
             | dependencies. People always bring Maven up as a system that
             | got it right, but Maven only does JVM things.
             | 
             | I think the real solution here is to just only use python
             | dependency management for python things and to use
             | something like nix for everything else.
        
               | adgjlsfhk1 wrote:
               | Julia's package manager (for one) works great and can
               | manage non Julia packages. the problem with python's
               | system is that rejecting semver makes writing a package
               | manager basically impossible since there is no way to
               | automatically resolve packages.
        
               | woodruffw wrote:
               | Could you clarify what you mean? pip and every other
               | Python package installer is absolutely doing automatic
               | package resolution, and the standard (PEP 440) dependency
               | operators include a compatible version operator (~=)
               | that's predicated on SemVer-style version behavior.
        
               | pletnes wrote:
               | This is what we used to have and it was much worse.
               | Source: lived that life 10-15 y ago.
        
               | __MatrixMan__ wrote:
               | 15y ago I was using apt-get to manage my c++ dependencies
               | with no way of keeping track of which dependency went
               | with which project. It was indeed pretty awful.
               | 
               | Now when I cd into a project, direnv + nix notices the
               | dependencies that that project needs and makes them
               | available, whatever their language. When I cd into a
               | different project, I get an entirely different set of
               | dependencies. There's pretty much nothing installed with
               | system scope. Just a shell and an editor.
               | 
               | Both of these are language agnostic, but the level of
               | encapsulation is quite different and one is much better
               | than that other. (There are still plenty of problems, but
               | they can be fixed with a commit instead of a change of
               | habit.)
               | 
               | The idea that every language needs a different package
               | manager and that each of those needs to package
               | everything that might my useful when called from that
               | language whether or not it is written in that language...
               | It just doesn't scale.
        
             | galdosdi wrote:
             | The shitshow that is python tooling is one of the reasons I
             | prefer java jobs to python jobs when I can help it. Java
             | got this pretty right years and years and years earlier.
             | Why are python and javascript continuing to horse around
             | playing games?
        
         | 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.
        
             | cwalv wrote:
             | It checks types .. it doesn't check type annotations.
             | 
             | Just try:                 $ Python       >>> 1 + '3'
        
           | 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.
        
               | zitterbewegung wrote:
               | I haven't used an IDE that has that but it is still just
               | giving you a hint that there is an error and the
               | interpreter is not throwing an error which was my point.
        
               | kortex wrote:
               | That's true of most compiled languages. Unless we are
               | talking about asserts, reflection, I think type erasure,
               | and maybe a few other concepts, language runtimes don't
               | check types. C does not check types at runtime. You
               | compile it and then rely on control of invariants and
               | data flow to keep everything on rails. In python, this is
               | tricky because _everything_ is behind at least one layer
               | of indirection, and thus virtually everything is mutable,
               | so it 's hard to enforce total control of all data
               | structures. But you can get really close with modern
               | tooling.
        
               | cwalv wrote:
               | >> and the interpreter is not throwing an error which was
               | my point. > That's true of most compiled languages
               | 
               | True of most statically typed languages (usually no need
               | to check at runtime), but not true in Python or other
               | dynamically typed languages. Python would have been
               | unusable for decades (prior to typehints) if that was
               | true.
        
               | kortex wrote:
               | That's just reflection. That's a feature of code, not
               | language runtime. I think there are some languages which
               | in fact have type checking in the runtime as a bona-fide
               | feature. Most won't, unless you do something like
               | isinstance()
        
               | setopt wrote:
               | > I haven't used an IDE that has that
               | 
               | You don't need an IDE for this, an LSP plugin + Pyright
               | is sufficient to get live type checking. For instance,
               | Emacs (Eglot), Vim (ALE), Sublime (SublimeLSP) all
               | support Pyright with nearly no setup required.
        
               | zo1 wrote:
               | > "I haven't used an IDE that has that but it is still
               | just giving you a hint that there is an error and the
               | interpreter is not throwing an error which was my point."
               | 
               | At this point, I'm not sure how one is to take your
               | opinion on this matter. Just like me coding some C# or
               | Java in notepad and then opining to a Java developer
               | audience about the state of their language and ecosystem.
        
             | kortex wrote:
             | Nope. Type annotations can be executed and accessed by the
             | runtime. That's how things like Pydantic, msgspec, etc, do
             | runtime type enforcement and coercion.
             | 
             | There are also multiple compilers (mypyc, nuitka, others I
             | forget) which take advantage of types to compile python to
             | machine code.
        
           | 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.
        
             | quotemstr wrote:
             | > In practice it's quite usable
             | 
             | It would be super helpful if the interpreter had a type-
             | enforcing mode though. All the various external runtime
             | enforcement packages leave something to be desired.
        
               | setopt wrote:
               | I agree. There are usable third-party runtime type
               | checkers though. I like Beartype, which lets you add a
               | decorator @beartype above any function or method, and
               | it'll complain at runtime if arguments or return values
               | violate the type hints.
               | 
               | I think runtime type checking is in some ways a better
               | fit for a highly dynamic language like Python than static
               | type checking, although both are useful.
        
           | 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.
        
               | kortex wrote:
               | https://github.com/python/mypy
               | 
               | > Python itself doesn't do that
               | 
               | The type syntax _is_ python. MyPy is part of Python. It
               | 's maintained by the python foundation. Mypy is not part
               | of _CPython_ because modularity is good, the same way
               | that ANSI C doesn 't compile anything, that's what gcc,
               | clang, etc are for.
               | 
               | Mojo is literally exactly the same way, the types are
               | optional, and the tooling handles type checking and
               | compilation.
        
               | GTP wrote:
               | > Mojo is literally exactly the same way.
               | 
               | No, because in Mojo, type checking is part of the
               | language specification: you need no external tool for
               | that. Python defines a _syntax_ that can be used for type
               | checking, but you need an external tool to do that. GCC
               | does type checking because it 's defined in the language
               | specification. You would have a situation analogous to
               | Python only if you needed GCC + some other tool for type
               | checking. This isn't the case.
        
               | zo1 wrote:
               | You're really splitting hairs here all to prove some sort
               | of "type checking isn't included with python" property.
               | Even if you're technically right, half the world really
               | doesn't care and most code being churned out in Python is
               | type-hinted, type-checked, and de-facto enforced at
               | design time.
               | 
               | It's honestly winning the long-term war because
               | traditional languages have really screwed things up with
               | infinite and contrived language constructs and attempts
               | just to satisfy some "language spec" and "compiler",
               | whilst still trying to be expressive enough for what
               | developers need and want to do safely. Python side-
               | stepped all of that, has the perfect mix of type-checking
               | and amazing "expressibility", and is currently proving
               | that it's the way forward with no stopping it.
        
               | GTP wrote:
               | I'm not saying that no one should use Python, I'm just
               | saying why I don't like it. But if you instead like it I
               | will not try to stop you using it.
               | 
               | This said, if most people use type hints and the proper
               | tooling to enforce type checking, I would say this would
               | be a good reason to properly integrate (optional) static
               | typing in the language: it shows that most programmers
               | like static typing. The problem I focused on in my
               | example isn't the only advantage of a type system.
        
           | 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?
        
               | GTP wrote:
               | It never happened to me, because I don't use Python ;)
               | 
               | On a more serious note, your comment actually hints at an
               | issue: unit testing is less effective without static type
               | checking. Let's assume I would like to sum x and y. I can
               | extensively test the function and see that it indeed
               | correctly sums two numbers. But then I need to call the
               | function somewhere in my code, and whether it will work
               | as intended or not depends on the context in which the
               | function is used. Sometimes the input you pass to a
               | function depends from some external source outside your
               | control, an if that's the case you have to resort to
               | manual type checking. Or use a properly typed language.
        
               | hot_gril wrote:
               | This isn't an actual problem people encounter in unit
               | testing, partially because you test your outer interfaces
               | first. Also, irl static types often get so big and
               | polymorphic that the context matters just as much.
        
               | 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.
        
               | hot_gril wrote:
               | Yeah and even with static typing, a string can be many
               | things. Some people even wrap their strings into
               | singleton structs to avoid something like sending a
               | customerId string into a func that wants an orderId
               | string, which I think is overkill. Same with int.
        
               | GTP wrote:
               | > It calls x.__add__(y)
               | 
               | Your answer doesn't solve the problem, it just moves it:
               | can you tell me what x. __add__(y) does?
        
               | andrewaylett wrote:
               | Whatever it's defined to do, and nothing else.
               | 
               | Dynamic typing, but strong typing.
               | 
               | There's no magic going on here, just an attribute lookup.
               | It's still possible to write terrible Python code -- as
               | it is in any language -- and the recommendation is still
               | "don't write terrible code", just as it is in any
               | language. You don't have to like it, but not liking it
               | won't make it any different.
               | 
               | The older I get, the more I like writing statically-typed
               | code. I wrote a _lot_ more Python (for my own use) in my
               | youth, and tend towards Rust nowadays. Speaking of which:
               | if you dislike the dynamic typing of Python then you must
               | _hate_ the static typing of Rust -- what does
               | fn add<T:Add<U>, U>(a: T, b: U) -> T::Output { a + b }
               | 
               | do?
        
               | 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.
        
               | vhcr wrote:
               | In theory it's nice that the compiler would catch those
               | kinds of problems, but in practice it doesn't matters.
        
               | GTP wrote:
               | It can matter also in practice. Once I was trying some
               | Python ML model to generate images. My script ran for 20
               | minutes to then terminate with an exception when it
               | arrived at the point of saving the result to a file. The
               | reason is that I wanted to concatenate a counter to the
               | file name, but forgot to wrap the integer into a call to
               | str(). 20 minutes wasted for an error that other
               | languages would have spotted before running the script.
        
               | cozzyd wrote:
               | It's very hard to write long-running daemons in python
               | partially for this reason, when you make a typo on a
               | variable or method name in an uncommon code path.
        
               | mixmastamyk wrote:
               | > you can't tell what a function does just by looking at
               | it
               | 
               | You just _did_ tell us what it does by looking at it, for
               | the 90% case at least. It might be useful to throw two
               | lists in there as well. Throw a custom object in there?
               | It will work if you planned ahead with dunder add and
               | radd. If not fix, implement, or roll back.
        
               | GTP wrote:
               | > You just did tell us what it does by looking at it, for
               | the 90% case at least
               | 
               | The problem is that you can't know if the function is
               | going to do what you want it to do without also looking
               | at the context in which it is used. And what you pass as
               | input could be dependent on external factors that you
               | don't control. So I prefer the languages that let me know
               | what happens in 100% of the cases.
        
               | mixmastamyk wrote:
               | Protection from untrusted input is something that has to
               | be considered in any language.
               | 
               | Not yet been a real world concern in my career, outside
               | webforms, which are handled by framework.
        
               | GTP wrote:
               | > Protection from untrusted input is something that has
               | to be considered in any language
               | 
               | Sure, but some languages make it easier than others. And
               | that was just one example, another example could be
               | having a branch where the input to your function depends
               | on some condition. You could have one of the two branches
               | passing the wrong types, but you will only notice when
               | that branch gets executed.
        
               | radarsat1 wrote:
               | And if you specify that they are numbers then you lose
               | the ability of the function to generalize to vectors.
               | 
               | Indeed assuming it adds two things is correct, and
               | knowing that concatenation is how Python defines adding
               | strings is important for using the language in the
               | intended way.
        
             | infamia wrote:
             | > 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
             | 
             | Python is strongly typed and it's interpreter is type aware
             | of it's variables, so you're probably overreaching with
             | that statement. Because Python's internals are type aware,
             | it's how folks are able to create type checkers like mypy
             | and pydantic both written in Python. Maybe you're thinking
             | about TS/JSDoc, which is just window dressing for IDEs to
             | display hints as you described?
        
               | GTP wrote:
               | I don't think you can say that a language is strongly
               | typed if only the language's internals are. The Python
               | interpreter prevents you from summing an integer to a
               | string, but only at runtime when in many cases it's
               | already too late. A strongly typed language would warn
               | you much sooner.
        
               | infamia wrote:
               | Your example is bang on when describing a "strongly
               | typed" language. That said, strongly typed is different
               | from "static typing", which is what you described later
               | in your post. Python is both strongly typed and
               | dynamically typed. It is all rather confusing and just a
               | big bowl of awful. I have to look up if I haven't
               | referenced it in a while, because the names are far too
               | similar and there aren't even good definitions around
               | some of the concepts.
               | 
               | https://stackoverflow.com/questions/2690544/what-is-the-
               | diff...
               | 
               | https://wiki.python.org/moin/Why%20is%20Python%20a%20dyna
               | mic...
        
             | kortex wrote:
             | s/will never be/already is/g
             | 
             | https://github.com/mypyc/mypyc
             | 
             | You can compile python to c. Right now. Compatibility with
             | extensions still needs a bit of work. But you can write
             | extremely strict python.
             | 
             | That's without getting into things like cython.
        
           | 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. The type-checking never
               | ended up catching any bugs, 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.
        
               | hot_gril wrote:
               | This is what made me give it a shot in TS, but the
               | problem is your types at interface boundaries tend to be
               | annoyingly complex. The other problem is any project with
               | optional types soon becomes a project with required types
               | everywhere.
               | 
               | There might be more merit in widely-used public
               | libraries, though. I don't make those.
        
             | grumpyprole wrote:
             | A type checker is only going to add limited value if you
             | don't put the effort in yourself. If everything string-like
             | is just a string, and if data is not parsed into types that
             | maintain invariants, then little is being constrained and
             | there is little to "check". It becomes increasingly
             | difficult the more sophisticated the type system is, but in
             | some statically typed languages like Coq, clever
             | programmers can literally prove the correctness of their
             | program using the type system. Whereas a unit test can only
             | prove the presence of bugs, not their absence.
        
           | NegativeK wrote:
           | Python's typing must accommodate Python's other goal as quick
           | scripting language. The solution is to document the optional
           | typing system as part of the language's spec and let other
           | tools do the checking, if a user wants to use them.
           | 
           | The other tools are trivially easy to set up and run (or let
           | your IDE run for you.) As in, one command to install, one
           | command to run. It's an elegant compromise that brings
           | something that's sorely needed to Python, and users will
           | spend more time loading the typing spec in their browser than
           | they will installing the type checker.
        
         | alfalfasprout wrote:
         | The conda-forge ecosystem is making big strides in dependency
         | management. No more are we stuck with the abysmal pip+venv
         | story.
        
           | falcor84 wrote:
           | I definitely like some aspects of conda, but at least pip
           | doesn't give me these annoying infinite "Solving environment"
           | loops [0].
           | 
           | [0] https://stackoverflow.com/questions/56262012/conda-
           | install-t...
        
             | setopt wrote:
             | That issue is fixed by using the libmamba resolver:
             | 
             | https://www.anaconda.com/blog/a-faster-conda-for-a-
             | growing-c...
        
         | ramses0 wrote:
         | You forgot:                   [X] print requires parentheses
        
           | nine_k wrote:
           | Fair. But it was importable from __future__ back in 2.7.
        
           | vulnbludog wrote:
           | Idk why but python 2 print still pops up in my nightmares lol
           | on bro
        
           | zarzavat wrote:
           | print was way better when it was a statement.
        
         | 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
        
           | noisy_boy wrote:
           | rye's habit of insisting on creating a .venv per project is a
           | deal-breaker. I don't want .venvs spread all over my projects
           | eating into space (made worse by the ml/LLM related mega
           | packages). It should atleast respect activated venvs.
        
             | nine_k wrote:
             | A venv per project is a very sane way. Put them into the
             | ignore file. Hopefully they also could live elsewhere in
             | the tree.
        
             | VeejayRampay wrote:
             | well that's good for you, but you're in the minority and
             | rye will end up being a standard anyway, just like uv and
             | ruff, because they're just so much better than the
             | alternatives
        
         | agumonkey wrote:
         | I'm eager to see what a simple JIT can bring to computing
         | energy savings on python apps.
        
           | KeplerBoy wrote:
           | I'd wager the energy savings could put multiple power plants
           | out of service.
           | 
           | I regularly encounter python code which takes minutes to
           | execute but runs in less than a second when replacing key
           | parts with compiled code.
        
         | whoiscroberts wrote:
         | Optional static typing, not really. Those type hints are not
         | used at runtime for performance. Type hint a var as a string
         | then set it to an init, that code still gonna try to execute.
        
           | zarzavat wrote:
           | > Those type hints are not used at runtime for performance.
           | 
           | This is not a requirement for a language to be statically
           | typed. Static typing is about catching type errors before the
           | code is run.
           | 
           | > Type hint a var as a string then set it to an int, that
           | code still gonna try to execute.
           | 
           | But it will fail type checking, no?
        
             | mondrian wrote:
             | The critique is that "static typing" is not really the
             | right term to use, even if preceded by "optional". "Type
             | hinting" or "gradual typing" maybe.
             | 
             | In static typing the types of variables don't change during
             | execution.
        
               | zarzavat wrote:
               | If there's any checking of types before program runs then
               | it's static typing. Gradual typing is a form of static
               | typing that allows you to apply static types to only part
               | of the code.
               | 
               | I'm not sure what you mean by variables not changing
               | types during execution in statically typed languages. In
               | many statically typed languages variables don't exist at
               | runtime, they get mapped to registers or stack
               | operations. Variables only exist at runtime in languages
               | that have interpreters.
               | 
               | Aside from that, many statically typed languages have a
               | way to declare dynamically typed variables, e.g. the
               | dynamic keyword in C#. Or they have a way to declare a
               | variable of a top type e.g. Object and then downcast.
        
               | neonsunset wrote:
               | 'dynamic' in C# is considered a design mistake and pretty
               | much no codebase uses it.
               | 
               | On the other hand F# is much closer to the kind of
               | gradual typing you are discussing.
        
               | mondrian wrote:
               | Python is dynamically typed because it type-checks at
               | runtime, regardless of annotations or what mypy said.
        
         | nhumrich wrote:
         | Python 3.12 introduces a little bit of JIT. Also, there is
         | always pypy.
         | 
         | For efficient dependency management, there is now rye and UV.
         | So maybe you can check all those boxes?
        
           | nine_k wrote:
           | Rye is pretty alpha, uv is young, too, and they are not part
           | of "core" Python, not under the Python Foundation umbrella
           | (like e.g. mypy is).
           | 
           | So there's plenty of well-founded hope, but the boxes are
           | still not checked.
        
       | 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.
        
             | rty32 wrote:
             | I think it is beneficial to some people, but not a lot. My
             | guess is that most Python users (from beginners to advanced
             | users, including many professional data scientists) have
             | never heard of GIL or thought of doing any parallelization
             | in Python _. Code that needs performance and would benefit
             | from multithreading, usually written by professional
             | software engineers, likely isn 't written in Python in the
             | first place. It would make sense for projects that can
             | benefit from disabling GIL without a ton of changes.
             | Remember it is not trivial to update single threaded code
             | to use multithreading _correctly _.
             | 
             | _ in Python language specifically. Their library may have
             | already done some form of parallelization under the hood
        
               | bdd8f1df777b wrote:
               | > Code that needs performance and would benefit from
               | multithreading, usually written by professional software
               | engineers, likely isn't written in Python in the first
               | place.
               | 
               | There are a lot of simple cases where multi-threading can
               | easily triple or quadruple the performance.
        
               | Certhas wrote:
               | But multiprocessing can't?
               | 
               | I used to write a ton of MPI based parallel python. It's
               | pretty straightforward. But one could easily imagine
               | trying to improve the multiprocessing ergonomics rather
               | than introducing threading. Obviously the people who made
               | the choice to push forward with this are aware of these
               | options, too. Still mildly puzzling to me why threads for
               | Python are needed/reasonable.
        
               | pdhborges wrote:
               | It doesn't to be puzzling just read the motivation
               | section of https://peps.python.org/pep-0703/
        
           | 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.
        
             | andmkl wrote:
             | Yes, but then extensions can already release the GIL and
             | use the simple and industrial strength std::thread, which
             | is orders of magnitude easier to debug.
        
               | woodruffw wrote:
               | Concurrent operations exist at all levels of the software
               | stack. Just because native extensions might want to
               | release the GIL and use OS threads doesn't mean pure
               | Python can't also want (or need) that.
               | 
               | (And as a side note: I have never, in around a decade of
               | writing C++, heard std::thread described as "easy to
               | debug.")
        
               | ipsod wrote:
               | Really? Cool.
               | 
               | I expected that dropping down to C/C++ would be a large
               | jump in difficulty and quantity of code, but I've found
               | it isn't, and the dev experience isn't entirely worse,
               | as, for example, in-editor code-intelligence is rock
               | solid and very fast in every corner of my code and the
               | libraries I'm using.
               | 
               | If anyone could benefit from speeding up some Python
               | code, I'd highly recommend installing cppyy and giving it
               | a try.
        
               | woodson wrote:
               | Thanks, I haven't come across cppyy! But I've worked with
               | pybind11, which works well, too.
        
               | ipsod wrote:
               | Sure! I tried pybind11, and some other things. cppyy was
               | the first I tried that didn't give me any trouble. I've
               | been using it pretty heavily for about a year, and still
               | no trouble.
        
               | nly wrote:
               | Last I checked cppyy didn't build any code with
               | optimisations enabled (same as cling)
        
               | ipsod wrote:
               | It seems like you might be able to enable some
               | optimizations with EXTRA_CLING_ARGS. Since it's based on
               | cling, it's probably subject to whatever limitations
               | cling has.
               | 
               | To be honest, I don't know much about the speed, as my
               | use-case isn't speeding up slow code.
        
           | wongarsu wrote:
           | I often reach for python multiprocessing for code that will
           | run $singleDigit number of times but is annoyingly slow when
           | run sequentially. I could never justify the additional
           | development time for using a more performant language, but I
           | can easily justify spending 5-10 minutes making the
           | embarrassingly parallel stuff execute in parallel.
        
             | throwaway81523 wrote:
             | I've generally been able to deal with embarassing
             | parallelism by just chopping up the input and running
             | multiple processes with GNU Parallel. I haven't needed the
             | multiprocessing module or free threading so far. I believe
             | CPython still relies on various bytecodes to run
             | atomically, which you get automatically with the GIL
             | present. So I wonder if hard-to-reproduce concurrency bugs
             | will keep surfacing in the free-threaded CPython for quite
             | some time.
             | 
             | I feel like all of this is tragic and Python should have
             | gone to a BEAM-like model some years ago, like as part of
             | the 2 to 3 transition. Instead we get async wreckage and
             | now free threading with its attendant hazards. Plus who
             | knows how many C modules won't be expecting this.
        
               | robertlagrant wrote:
               | Async seems fine? What's wrong with it?
        
               | throwaway81523 wrote:
               | Watch this video and maybe you'll understand ;). Warning,
               | NSFW (lots of swearing), use headphones.
               | 
               | https://www.youtube.com/watch?v=bzkRVzciAZg
               | 
               | This is also good:
               | 
               | https://journal.stuffwithstuff.com/2015/02/01/what-color-
               | is-...
               | 
               | web search on "colored functions" finds lots of
               | commentary on that article.
        
               | wesselbindt wrote:
               | I've always found the criticism leveled by the colored
               | functions blog post a bit contrived. Yes, when you
               | replace the words async/await with meaningless concepts I
               | do not care about, it's very annoying to have to
               | arbitrarily mark a function as blue or red. But when you
               | replace the word "aync" with something like "expensive",
               | or "does network calls", it becomes clear that
               | "async/await" makes intrinsic properties about your code
               | (e.g., is it a bad idea to put this call in a loop from a
               | performance perspective) explicit rather than implicit.
               | 
               | In short, "await" gives me an extra piece of data about
               | the function, without having to read the body of the
               | function (and the ones it calls, and the ones they call,
               | etc). That's a good thing.
               | 
               | There are serious drawbacks to async/await, and the
               | red/blue blog post manages to list none of them.
               | 
               | EDIT: all of the above is predicated on the idea that
               | reading code is harder than writing it. If you believe
               | the opposite, then blue/red has a point.
        
               | adament wrote:
               | But a synchronous function can and many do make network
               | calls or write to files. It is a rather vague signal
               | about the functions behavior as opposed to the lack of
               | the IO monad in Haskell.
               | 
               | To me the difficulty is more with writing generic code
               | and maintaining abstraction boundaries. Unless the
               | language provides a way to generalise over asyncness of
               | functions, we need a combinatorial explosion of async
               | variants of generic functions. Consider a simple filter
               | algorithm it needs versions for: (synchronous vs
               | asynchronous iterator) times (synchronous vs asynchronous
               | predicate). We end up with a pragmatic but ugly solution:
               | provide 2 versions of each algorithm: an async and a
               | sync, and force the user of the async one to wrap their
               | synchronous arguments.
               | 
               | Similarly changing some implementation detail of a
               | function might change it from a synchronous to an
               | asynchronous function, and this change must now propagate
               | through the entire call chain (or the function must start
               | its own async runtime). Again we end up in a place where
               | the most future proof promise to give for an abstraction
               | barrier is to mark everything as async.
        
               | wesselbindt wrote:
               | > But a synchronous function can and many do make network
               | calls or write to files
               | 
               | This, for me, is the main drawback of async/await, at
               | least as it is implemented in for example Python. When
               | you call a synchronous function which makes network
               | calls, then it blocks the event loop, which is pretty
               | disastrous, since for the duration of that call you lose
               | all concurrency. And it's a fairly easy footgun to set
               | off.
               | 
               | > It is a rather vague signal about the functions
               | behavior as opposed to the lack of the IO monad in
               | Haskell.
               | 
               | I'm happy you mentioned the IO monad! For me, in the
               | languages people pay me to write in (which sadly does not
               | include Haskell or F#), async/await functions as a poor
               | man's IO monad.
               | 
               | > Again we end up in a place where the most future proof
               | promise to give for an abstraction barrier is to mark
               | everything as async.
               | 
               | Yes, this is one way to write async code. But to me this
               | smells the same as writing every Haskell program as a
               | giant do statement because the internals might want to do
               | I/O at some point. Async/await makes changing side-effect
               | free internals to effectful ones painful, which pushes
               | you in the direction of doing the I/O at the boundaries
               | of your system (where it belongs), rather than all over
               | the place in your call stack. In a ports-adapters
               | architecture, it's perfectly feasible to restrict network
               | I/O to your service layer, and leave your domain entirely
               | synchronous. E.g. sth like                 async def
               | my_service_thing(request, database):
               | my_business_object = await
               | database.get(request.widget_id)
               | my_business_object.change_state(request.new_widget_color)
               | # some complicated, entirely synchronous computation
               | await database.save(my_business_object)
               | 
               | Async/await pushes you to code in a certain way that I
               | believe makes a codebase more maintainable, in a way
               | similar to the IO monad. And as with the IO monad, you
               | can subvert this push by making everything async (or
               | writing everything in a do statement), but there's better
               | ways of working with them, and judging them based on this
               | subversion is not entirely fair.
               | 
               | > ugly solution: provide 2 versions of each algorithm: an
               | async and a sync
               | 
               | I see your point, and I think it's entirely valid. But
               | having worked in a couple async codebases for a couple of
               | years, the amount of stuff I (or one of my collaborators)
               | have had to duplicate for this reason I think I can count
               | on one hand. It seems that in practice this cost is a
               | fairly low one.
        
               | pansa2 wrote:
               | > _when you replace the word "aync" with something like
               | "expensive", or "does network calls", it becomes clear
               | that "async/await" makes intrinsic properties about your
               | code explicit rather than implicit._
               | 
               | Do you think we should be annotating functions with
               | `expensive` and/or `networking`? And also annotating all
               | of their callers, recursively? And maintaining 4 copies
               | of every higher-order function depending on whether the
               | functions it calls are `expensive`, `networking`, neither
               | or both?
               | 
               | No, we rely on documentation for those things, and IMO we
               | should for `async` as well. The reason we can't, and why
               | `async`/`await` exist, is because of shortcomings (lack
               | of support for stackful coroutines) in language runtimes.
               | The best solution is to fix those shortcomings, not add
               | viral annotations everywhere.
        
               | hiddew wrote:
               | > The reason we can't, and why `async`/`await` exist, is
               | because of shortcomings (lack of support for stackful
               | coroutines) in language runtimes
               | 
               | The JVM runtime has solved this problem neatly with
               | virtual threads in my opinion. Run a web request in a
               | virtual thread, and all blocking I/O is suddenly no
               | longer blocking the OS thread, but yielding/suspending
               | and giving and giving another virtual thread run time.
               | And all that without language keywords that go viral
               | through your program.
        
               | pansa2 wrote:
               | Yes, this is similar to how Go works. IIRC the same
               | approach was available in Python as a library,
               | "greenlet", but Python's core developers rejected it in
               | favour of `async`/`await`.
        
               | throwaway81523 wrote:
               | The Python community seems to have a virulent hatred of
               | threads. I don't understand the reason. Yes there are
               | hazards but you can code in a style that avoids them.
               | With something like BEAM you can even enforce the style.
               | Async/await of course introduce their own hazards.
        
               | wesselbindt wrote:
               | So here I think we differ fundamentally in how we like to
               | read code. I much prefer being able to quickly figure out
               | things of interest about a function by glancing at its
               | signature, rather than look at documentation, or worse,
               | having to read the implementation of the function and the
               | functions it calls (and so on, recursively).
               | 
               | For example, I much prefer a signature like
               | def f(a: int) -> str:
               | 
               | over                 def f(a):
               | 
               | because it allows me to see, without reading the
               | implementation of the function (or, if it exists, and I'm
               | willing to bet on its reliability, the documentation),
               | that it takes an integer, and gives me a string. And yes,
               | this requires that I write viral type annotations on all
               | my functions when I write them, but for me the bottleneck
               | at my job is not writing the code, it's reading it. So
               | that's a small upfront cost I'm very much willing to pay.
               | 
               | > Do you think we should be annotating functions with
               | `expensive` and/or `networking`? And also annotating all
               | of their callers, recursively?
               | 
               | Yes, absolutely, and yes, absolutely. That's just being
               | upfront and honest about an intrinsic property of those
               | functions. A function calling a function that does
               | network I/O by transitivity also does network I/O. I
               | prefer code that's explicit over code that's implicit.
        
               | pansa2 wrote:
               | > _Yes, absolutely, and yes, absolutely._
               | 
               | Fair enough, that's a valid philosophy, and one in which
               | `async`/`await` makes perfect sense.
               | 
               | However, it's not Python's philosophy - a language with
               | dynamic types, unchecked exceptions, and racy
               | multithreading. In Python, `async`/`await` seems to be at
               | odds with other language features - it feels like it's
               | more at home in a language like Rust.
        
               | wesselbindt wrote:
               | I completely agree with you. However I've always found
               | the dynamic typing approach to be a bit at odds with
               | python3 -c "import this" | head -4 | tail -1
               | 
               | I think the fast and loose style that Python enables is
               | perfect for small scripts and one off data science
               | notebooks and the like. But having worked in large
               | codebases which adopt the same style, and ones that avoid
               | it through static typing and in some cases async/await,
               | the difference in productivity I've noticed in both me
               | and my collaborators is too stark for me to ignore.
               | 
               | I think I should've been more nuanced in my comments
               | praising async/await. I believe that what I say is valid
               | in large IO-bound applications which go beyond basic CRUD
               | operations. In general it depends, of course.
        
               | pansa2 wrote:
               | > _I think the fast and loose style that Python enables
               | is perfect for small scripts and one off data science
               | notebooks and the like._
               | 
               | Agreed - I only use Python for scripts like this,
               | preferring statically-typed, AOT-compiled languages for
               | larger programs.
               | 
               | That's why I think Python should have adopted full
               | coroutines - it should play to its strengths and stick to
               | its fast-and-loose style. However, the people who decide
               | how the language evolves are all employees of large
               | companies using it for large codebases - their needs are
               | very different from people who are only using Python for
               | small scripts.
        
               | gpderetta wrote:
               | Except that at least in python async doesn't mean that.
               | Non async functions can do networking, block, or do
               | expensive operations.
               | 
               | On the other hand async functions can be very cheap.
               | 
               | Again, which useful property does async protect?
        
           | eigenvalue wrote:
           | I personally optimize more for development time and overall
           | productivity in creating and refactoring, adding new
           | features, etc. I'm just so much faster using Python than
           | anything else, it's not even close. There is such an
           | incredible world of great libraries easily available on pip
           | for one thing.
           | 
           | Also, I've found that ChatGPT/Claude3.5 are much, much
           | smarter and better at Python than they are at C++ or Rust. I
           | can usually get code that works basically the first or second
           | time with Python, but very rarely can do that using those
           | more performant languages. That's increasingly a huge concern
           | for me as I use these AI tools to speed up my own development
           | efforts very dramatically. Computers are so fast already
           | anyway that the ceiling for optimization of network oriented
           | software that can be done in a mostly async way in Python is
           | already pretty compelling, so then it just comes back again
           | to developer productivity, at least for my purposes.
        
             | indigodaddy wrote:
             | Ever messed about with Claude and php?
        
               | lanstin wrote:
               | I don't think we are supposed to use HN for humor only
               | posts.
        
               | jacob019 wrote:
               | lol
        
               | saagarjha wrote:
               | You think wrong
        
               | indigodaddy wrote:
               | Why the downvotes? Totally serious question. Jesus Christ
               | HN
        
             | goosejuice wrote:
             | Kind of sounds like you are optimizing for convenience :)
        
           | jodrellblank wrote:
           | https://www.servethehome.com/wp-
           | content/uploads/2023/01/Inte...
           | 
           | AMD EPYC 9754 with 128-cores/256-threads, and EPYC 9734 with
           | 112-cores/224-threads. TomsHardware says they "will compete
           | with Intel's 144-core Sierra Forest chips, which mark the
           | debut of Intel's Efficiency cores (E-cores) in its Xeon data
           | center lineup, and Ampre's 192-core AmpereOne processors".
           | 
           | What in 5 years? 10? 20? How long will "1 core should be
           | enough for anyone using Python" stand?
        
             | d0mine wrote:
             | Number crunching code in Python (such as using
             | numpy/pytorch) performs the vast vast majority of its
             | calculations in C/Fortran code under the hood where GIL can
             | be released. Single python process can use multiple CPUs.
             | 
             | There is code that may benefit from the free threaded
             | implementation but it is not as often as it might appear
             | and it is not without its own downsides. In general, GIL
             | simplifies multithreaded code.
             | 
             | There were no-GIL Python implementations such as Jython,
             | IronPython. They hadn't replaced CPython, Pypy
             | implementation which use GIL i.e., other concerns dominate.
        
               | imachine1980_ wrote:
               | Yes but jython am iron aren't the standard, and I feel
               | the more relevant part is inertia, puppy is design whit
               | lots of concern of compatibility, then being the new
               | standard can totally make difference making both cases
               | not a good comparison.
        
           | Derbasti wrote:
           | A thought experiment:
           | 
           | A piece of code takes 6h to develop in C++, and 1h to run.
           | 
           | The same algorithm takes 3h to code in Python, but 6h to run.
           | 
           | If I could thread-spam that Python code on my 24 core
           | machine, going Python would make sense. I've certainly been
           | in such situations a few times.
        
             | Certhas wrote:
             | C++ and python are not the only options though.
             | 
             | Julia is one that is gaining a lot of use in academia, but
             | any number of modern, garbage collected compiled high level
             | languages could probably do.
        
               | rbanffy wrote:
               | Fair. Add a couple hours to learn enough Julia to write
               | the code.
        
           | tho34234234 wrote:
           | It's not just about "raw-flop performance" though; it affects
           | even basic things like creating data-loaders that run in the
           | background while your main thread is doing some hard ML
           | crunching.
           | 
           | Every DL library comes with its own C++ backend that does
           | this for now, but it's annoyingly inflexible. And dealing
           | with GIL is a nightmare if you're dealing with mixed Python
           | code.
        
           | jillesvangurp wrote:
           | Right now you are right. This is about taking away that
           | argument. There's no technical reason for this to stay true.
           | Other than that the process of fixing this is a lot of work
           | of course. But now that the work has started, it's probably
           | going to progress pretty steadily.
           | 
           | It will be interesting to see how this goes over the next few
           | years. My guess is that a lot of lessons were learned from
           | the python 2 to 3 move. This plan seems pretty solid.
           | 
           | And of course there's a relatively easy fix for code that
           | can't work without a GIL: just do what people are doing today
           | and just don't fork any threads in python. It's kind of
           | pointless in any case with the GIL in place so not a lot of
           | code actually depends on threads in python.
           | 
           | Preventing the forking of threads in the presence of things
           | still requiring the GIL sounds like a good plan. This is a
           | bit of meta data that you could build into packages. This
           | plan is actually proposing keeping track of what packages
           | work without a GIL. So, that should keep people safe enough
           | if dependency tools are updated to make use of this meta data
           | and actively stop people from adding thread unsafe packages
           | when threading is used.
           | 
           | So, I have good hopes that this is going to be a much
           | smoother transition than python 2 to 3. The initial phase is
           | probably going to flush out a lot of packages that need
           | fixing. But once those fixes start coming in, it's probably
           | going to be straightforward to move forward.
        
           | paulddraper wrote:
           | > should not be written
           | 
           | IDK what l should and shouldn't be written in, but there are
           | a very large # of proud "pure Python" libraries on GitHub and
           | HN.
           | 
           | The ecosystem seems to even prefer them.
        
         | saurik wrote:
         | FWIW, I think the concern though is/was that for most of us who
         | aren't doing shared-data multiprocessing this is going to make
         | Python even slower; maybe they figured out how to avoid that?
        
           | eigenvalue wrote:
           | Pretty sure they offset any possible slowdowns by doing
           | heroic optimizations in other parts of CPython. There was
           | even some talk about keeping just those optimizations and
           | leaving the GIL in place, but fortunately they went for the
           | full GILectomy.
        
         | quotemstr wrote:
         | What about the pessimization of single-threaded workloads? I'm
         | still not convinced a completely free-threaded Python is better
         | overall than a multi-interpreter, separate-GIL model with
         | explicit instead of implicit parallelism.
         | 
         | Everyone wants parallelism in Python. Removing the GIL isn't
         | the only way to get it.
        
         | Demiurge wrote:
         | Massive overhead of multiprocessing? How have I not noticed
         | this for tens of years?
         | 
         | I use coroutines and multiprocessing all the time, and saturate
         | every core and all the IO, as needed. I use numpy, pandas,
         | xarray, pytorch, etc.
         | 
         | How did this terrible GIL overhead completely went unnoticed?
        
           | viraptor wrote:
           | > I use numpy, pandas, xarray, pytorch, etc.
           | 
           | That means your code is using python as glue and you do most
           | of your work completely outside of cPython. That's why you
           | don't see the impact - those libraries drop GIL when you use
           | them, so there's much less overhead.
        
             | quietbritishjim wrote:
             | The parent commenter said they're using the multiprocessing
             | module, so it's irrelevant to them whether those modules
             | drop the GIL (except for the fact that they are missing an
             | opportunity to using threading instead). The overhead being
             | referred to, whether significant or not, is that of
             | spawning processes and doing IPC.
        
         | pizza234 wrote:
         | > using simple threads instead of dealing with the massive
         | overhead and complexity and bugs of using something like
         | multiprocessing.
         | 
         | Depending on the domain, the reality can be the reverse.
         | 
         | Multiprocessing in the web serving domain, as in "spawning
         | separate processes", is actually simpler and less bug-prone,
         | because there is considerably less resource sharing. The
         | considerably higher difficulty of writing, testing and
         | debugging parallel code is evident to anybody who's worked on
         | it.
         | 
         | As for the overhead, this again depends on the domain. It's
         | hard to quantify, but generalizing to "massive" is not
         | accurate, especially for app servers with COW support.
        
           | skissane wrote:
           | Just the other day I was trying to do two things in parallel
           | in Python using threads - and then I switched to
           | multiprocessing - why? I wanted to immediately terminate one
           | thing whenever the other failed. That's straightforwardly
           | supported with multiprocessing. With threads, it gets a lot
           | more complicated and can involve things with dubious
           | supportability
        
             | lyu07282 wrote:
             | There is a reason why it's "complicated" in threads,
             | because doing it correctly just IS complicated, and the
             | same reason applies to child processes, you just ignored
             | that reason. That's one example of a footgun in using
             | multiprocessing, people write broken code but they don't
             | know that because it appears to work... until it doesn't
             | (in production on friday night).
        
               | skissane wrote:
               | I don't agree. A big reason why abruptly terminating
               | threads at an arbitrary point is risky is it can corrupt
               | shared memory. If you aren't using shared memory in a
               | multiprocess solution, that's not an issue. Another big
               | reason is it can lead to resource leaks (e.g. thread gets
               | terminated in a finally clause to close resources and
               | hence the resource doesn't get closed). Again, that's
               | less of an issue for processes, since many resources
               | (file descriptors, network connections) get automatically
               | closed by the OS kernel when the process exits.
               | 
               | Abruptly terminating a child process still can
               | potentially cause issues, but there are whole categories
               | of potential issues which exist for abrupt thread
               | termination but not for abrupt process termination.
        
           | bausgwi678 wrote:
           | Using multiple processes is simpler in terms of locks etc,
           | but python libraries like multiprocessing or even
           | subprocess.popen[1] which make using multiple processes seem
           | easy are full of footguns which cause deadlocks due to fork-
           | safe code not being well understood. I've seen this lead to
           | code 'working' and being merged but then triggering sporadic
           | deadlocks in production after a few weeks.
           | 
           | The default for multiprocessing is still to fork (fortunately
           | changing in 3.14), which means all of your parent process'
           | threaded code (incl. third party libraries) has to be fork-
           | safe. There's no static analysis checks for this.
           | 
           | This kind of easy to use but incredibly hard to use safely
           | library has made python for long running production services
           | incredibly painful in my experience.
           | 
           | [1] Some arguments to subprocess.popen look handy but
           | actually cause python interpreter code to be executed after
           | the fork and before the execve, which has caused production
           | logging-related deadlocks for me. The original author was
           | very bright but didn't notice the footgun.
        
             | ignoramous wrote:
             | > _The default for multiprocessing is still to fork
             | (fortunately changing in 3.14)_
             | 
             | If I may: Changing from _fork_ to what?
        
               | thomasjudge wrote:
               | "In Python 3.14, the default will be changed to either
               | "spawn" or "forkserver" (a mostly safer alternative to
               | "fork")."
               | 
               | - https://pythonspeed.com/articles/python-
               | multiprocessing/
        
             | lyu07282 wrote:
             | Same experiences, multiprocessing is such a pain in python.
             | It's one of these things people think they can write
             | production code in, but they just haven't run into all the
             | ways their code was wrong so they figure out those bugs
             | later in production.
             | 
             | As an aside I still constantly see side effects in imports
             | in a ton of libraries (up to and including resource
             | allocations).
        
         | wokwokwok wrote:
         | > there is just a tremendous amount of performance that can be
         | automatically unlocked with almost no incremental effort for so
         | many organizations and projects
         | 
         | This just isn't true.
         | 
         | This does not improve single threaded performance (it's worse)
         | and concurrent programming is already available.
         | 
         | This will make it _less annoying_ to do concurrent processing.
         | 
         | It also makes _everything_ slower (arguable where that ends up,
         | currently _significantly slower_ ) overall.
         | 
         | This way over hyped.
         | 
         | At the end of the day this will be a change that (most likely)
         | makes the existing workloads for everyone slightly slower and
         | makes the lives of a few people a bit easier when they
         | implement natively parallel processing like ML easier and
         | better.
         | 
         | It's an incremental win for the ML community, and a
         | meaningless/slight loss for everyone else.
         | 
         | At the cost of a great. Deal. Of. Effort.
         | 
         | If you're excited about it because of the hype and don't really
         | understand it, probably calm down.
         | 
         | Mostly likely, at the end of the day, it s a change that is
         | totally meaningless to you, won't really affect you other than
         | making some libraries you use a bit faster, and others a bit
         | slower.
         | 
         | Overall, your standard web application will run a bit slower as
         | a result of it. You probably won't notice.
         | 
         | Your data stack will run a bit faster. That's nice.
         | 
         | That's it.
         | 
         | Over hyped. 100%.
        
           | anwlamp wrote:
           | Yes, good summary. My prediction is that free-threading will
           | be the default at some point because one of the corporations
           | that usurped Python-dev wants it.
           | 
           | The rest of us can live with arcane threading bugs and yet
           | another split ecosystem. As I understand it, if a single
           | C-extension opts for the GIL, the GIL will be enabled.
           | 
           | Of course the invitation to experiment is meaningless.
           | CPython is run by corporations, many excellent developers
           | have left and people will not have any influence on the
           | outcome.
        
             | pansa2 wrote:
             | > _one of the corporations that usurped Python-dev_
             | 
             | Man, that phrase perfectly encapsulates _so much_ of
             | Python's evolution over the last ~10 years.
        
           | Uptrenda wrote:
           | Why would it make single threaded performance slower? Sorry,
           | but that's kind of ridiculous. You're just making shit up at
           | this point.
        
             | QkdhagA wrote:
             | What is "it"?
             | 
             | If you assume two completely separate implementations where
             | there is an _#ifdef_ every 10 lines and atomics and locking
             | only occur with _--disable-gil_ , there is no slowdown for
             | the _--enable-gil_ build.
             | 
             | I don't think that is entirely the case though!
             | 
             | If the _--enable-gil_ build becomes the default in the
             | future, then peer pressure and packaging discipline will
             | force everyone to use it. Then you have the OBVIOUS
             | slowdown of atomics and of locking the reference counting
             | and in other places.
             | 
             | The advertised figures were around 20%, which would be
             | offset by minor speedups in other areas. But if you compare
             | against Python 3.8, for instance, the slowdowns are still
             | there (i.e., not offset by anything). Further down on the
             | second page of this discussion numbers of 30-40% have been
             | measured by the submitter of this blog post.
             | 
             | Actual benchmarks of Python tend to be suppressed or
             | downvoted, so they are not on the first page. The Java
             | HotSpot VM had a similar policy that forbid benchmarks.
        
         | Galanwe wrote:
         | > 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.
         | 
         | I'm saturating 192cpu / 1.5TBram machines with no headache and
         | straightforward multiprocessing. I really don't see what
         | multithreading will bring more.
         | 
         | What are these massive overheads / complexity / bugs you're
         | talking about ?
        
         | quietbritishjim wrote:
         | If you're worried about performance then much of your CPU time
         | is probably spent in a C extension (e.g. numpy, scipy, opencv,
         | etc.). Those all release the GIL so already allow
         | parallelisation in multiple threads. That even includes many
         | functions in the standard library (e.g. sqlite3, zip/unzip).
         | I've used multiple threads in Python for many years and never
         | needed to break into multiprocessing.
         | 
         | But, for sure, nogil will be good for those workloads written
         | in pure Python (though I've personally never been affected by
         | that).
        
       | 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. 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.
             | 
             | This post is a call to ask people to "kick the tires",
             | experiment, and report issues they run into, not announcing
             | that all work is done.
        
           | andmkl wrote:
           | That would be in the order of previous GIL-removal projects,
           | which were abandoned for that reason.
        
           | imtringued wrote:
           | That kind of negates the whole purpose of multi threading. An
           | application running on two cores might end up slower, not
           | faster. We know that the python developers are kind of
           | incompetent when it comes to performance, but the numbers you
           | are quoting are so bad they probably aren't correct in the
           | first place.
        
         | 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.
        
         | nhumrich wrote:
         | Irrelevant, because even if there was, you would use the normal
         | GIL python for it.
        
       | 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.
        
               | stavros wrote:
               | Oh, very interesting, that's a great solution then.
        
               | geekone wrote:
               | Looks like according to the PEP it may eventually be
               | default in 4-6 releases down the road:
               | https://peps.python.org/pep-0703/#python-build-modes
        
               | metadat wrote:
               | The article states the goal is to eventually (after some
               | years of working out the major kinks and performance
               | regressions) promote Free-Threaded Python to be the
               | default cPython distribution.
        
             | dagenix wrote:
             | As I understand it, if your code would have race conditions
             | with free threaded python, than it probably already has
             | them.
        
               | stavros wrote:
               | Not when there's a global interpreter lock.
        
               | pdonis wrote:
               | The GIL does not prevent race conditions in your Python
               | code. It only prevents race conditions in internal data
               | structures inside the interpreter and in atomic
               | operations, i.e., operations that take a single Python
               | bytecode. But many things that appear atomic in Python
               | code take more than one Python bytecode. The GIL gives
               | you no protection if you do such operations in multiple
               | threads on the same object.
        
               | stavros wrote:
               | I answered in a sibling reply:
               | https://news.ycombinator.com/item?id=40950798
        
               | pdonis wrote:
               | I'll respond there.
        
               | vulnbludog wrote:
               | I'm a dummy don't know nothing about coding but I love HN
               | usernames lol
        
               | matsemann wrote:
               | I think what many will experience, is that they want to
               | switch to multithreading without GIL, but learn they have
               | code that will have race conditions. But that _don 't_
               | have race conditions today, as it's run as multiple
               | processes, and not threads.
               | 
               | For instance our webserver. It uses multiple processes.
               | Each request then can modify some global variable, use as
               | cache or whatever, and only after it's completely done
               | handling the request the same process will serve a new
               | request. But when people see the GIL is gone, they
               | probably would like to start using it. Can handle more
               | requests without spamming processes / using beefy
               | computer with lots of RAM etc.
               | 
               | And then one might discover new race conditions one never
               | really had before.
        
               | dagenix wrote:
               | Are you writing an extension or Python code?
               | 
               | If you are writing Python code, the GIL can already be
               | dropped at pretty much any point and there isn't much way
               | of controlling when. Iirc, this includes in the middle of
               | things like +=. There are some operations that Python
               | defines as atomic, but, as I recall, there aren't all
               | that many.
               | 
               | In what way is the GIL preventing races for your use
               | case?
        
               | stavros wrote:
               | I mean that, if the GIL didn't prevent races, it would be
               | trivially removable. Races that are already there in
               | people's Python code have probably been debugged (or at
               | least they are tolerated), so there are some races that
               | will happen when the GIL is removed, and they will be a
               | surprise.
        
               | dagenix wrote:
               | The GIL prevents the corruption of Pythons internal
               | structures. It's hard to remove because:
               | 
               | 1. Lots of extensions, which can control when they
               | release the GIL unlike regular Python code, depend on it
               | 2. Removing the GIL requires some sort of other mechanism
               | to protect internal Python stuff 3. But for a long time,
               | such a mechanism was resisted by th Python team because
               | all attempts to remove the GIL either made single
               | threaded code slower or were considered too complicated.
               | 
               | But, as far as I understand, the GIL does somewhere
               | between nothing and very little to prevent races in pure
               | Python code. And, my rough understanding, is that
               | removing the GIL isn't expected to really impact pure
               | Python code.
        
               | stavros wrote:
               | Hmm, that's interesting, thank you. I didn't realize
               | extensions can control the GIL.
        
               | dagenix wrote:
               | Yup, I think its described here:
               | https://docs.python.org/3/c-api/init.html#releasing-the-
               | gil-....
               | 
               | My understanding, is that many extensions will release
               | the GIL when doing anything expensive. So, if you are
               | doing CPU or IO bound operations in an extension _and_
               | you are calling that operation in multiple threads, even
               | with the GIL you can potentially fully utilize all of the
               | CPUs in your machine.
        
               | pdonis wrote:
               | _> removing the GIL isn 't expected to really impact pure
               | Python code._
               | 
               | If your Python code assumes it's just going to run in a
               | single thread now, and it is run in a single thread
               | without the GIL, yes, removing the GIL will make no
               | difference.
        
               | dagenix wrote:
               | > If your Python code assumes it's just going to run in a
               | single thread now, and it is run in a single thread
               | without the GIL, yes, removing the GIL will make no
               | difference.
               | 
               | I'm not sure I understand your point.
               | 
               | Yes, singled thread code will run the same with or
               | without the GIL.
               | 
               | My understanding, was that multi-threaded pure-Python
               | code would also run more or less the same without the
               | GIL. In that, removing the GIL won't introduce races into
               | pure-Python code that is already race free with the GIL.
               | (and that relatedly, pure-Python code that suffers from
               | races without the GIL also already suffers from them with
               | the GIL)
               | 
               | Are you saying that you expect that pure-Python code will
               | be significantly impacted by the removal of the GIL? If
               | so, I'd love to learn more.
        
               | pdonis wrote:
               | _> removing the GIL won 't introduce races into pure-
               | Python code that is already race free with the GIL._
               | 
               | What do you mean by "race free"? Do you mean the code
               | expects to be run in multiple threads and uses the tools
               | provided by Python, such as locks, mutexes, and
               | semaphores, to ensure thread safety, and has been tested
               | to ensure that it is race free when run multi-threaded?
               | If that is what you mean, then yes, of course such code
               | will still be race free without the GIL, because it was
               | never depending on the GIL to protect it in the first
               | place.
               | 
               | But there is a lot of pure Python code out there that is
               | _not_ written that way. Removal of the GIL would allow
               | such code to be naively run in multiple threads using,
               | for example, Python 's support for thread pools. Anyone
               | under the impression that removing the GIL was intended
               | to allow this sort of thing without any further checking
               | of the code is mistaken. That is the kind of thing my
               | comment was intended to exclude.
        
               | dagenix wrote:
               | > But there is a lot of pure Python code out there that
               | is not written that way. Removal of the GIL would allow
               | such code to be naively run in multiple threads using,
               | for example, Python's support for thread pools.
               | 
               | I guess this is what I don't understand. This code could
               | already be run in multiple threads today, with a GIL. And
               | it would be broken - in all the same ways it would be
               | broken without a GIL, correct?
               | 
               | > Anyone under the impression that removing the GIL was
               | intended to allow this sort of thing without any further
               | checking of the code is mistaken. That is the kind of
               | thing my comment was intended to exclude.
               | 
               | Ah, so, is your point that removing the GIL will cause
               | people to take non-multithread code and run it in
               | multiple threads without realizing that it is broken in
               | that context? That its not so much a technical change,
               | but a change of perception that will lead to issues?
        
               | pdonis wrote:
               | _> This code could already be run in multiple threads
               | today, with a GIL._
               | 
               | Yes.
               | 
               |  _> And it would be broken - in all the same ways it
               | would be broken without a GIL, correct?_
               | 
               | Yes, but the absence of the GIL would make race
               | conditions more likely to happen.
               | 
               |  _> is your point that removing the GIL will cause people
               | to take non-multithread code and run it in multiple
               | threads without realizing that it is broken in that
               | context?_
               | 
               | Yes. They could run it in multiple threads with the GIL
               | today, but as above, race conditions might not show up as
               | often, so it might not be realized that the code is
               | broken. But also, with the GIL there is the common
               | perception that Python doesn't do multithreading well
               | anyway, so it's less likely to be used for that. With the
               | GIL removed, I suspect many people will want to use
               | multithreading a lot more in Python to parallelize code,
               | without fully realizing the implications.
        
               | dagenix wrote:
               | > Yes, but the absence of the GIL would make race
               | conditions more likely to happen.
               | 
               | Does it though? I'm not saying it doesn't, I'm quite
               | curious. Switching between threads with the GIL is
               | already fairly unpredictable from the perspective of
               | pure-Python code. Does it get significantly more
               | troublesome without the GIL?
               | 
               | > Yes. They could run it in multiple threads with the GIL
               | today, but as above, race conditions might not show up as
               | often, so it might not be realized that the code is
               | broken. But also, with the GIL there is the common
               | perception that Python doesn't do multithreading well
               | anyway, so it's less likely to be used for that. With the
               | GIL removed, I suspect many people will want to use
               | multithreading a lot more in Python to parallelize code,
               | without fully realizing the implications.
               | 
               | Fair
        
               | pdonis wrote:
               | _> Switching between threads with the GIL is already
               | fairly unpredictable from the perspective of pure-Python
               | code._
               | 
               | But it still prevents multiple threads from running
               | Python bytecode at the same time: in other words, at any
               | given time, only one Python bytecode can be executing in
               | the entire interpreter.
               | 
               | Without the GIL that is no longer true; an arbitrary
               | number of threads can all be executing a Python bytecode
               | at the same time. So even Python-level operations that
               | only take a single bytecode now must be protected to be
               | thread-safe--where under the GIL, they didn't have to be.
               | That is a significant increase in the "attack surface",
               | so to speak, for race conditions in the absence of thread
               | safety protections.
               | 
               | (Note that this does mean that even multi-threaded code
               | that was race-free with the GIL due to using explicit
               | locks, mutexes, semaphores, etc., might not be without
               | the GIL _if_ those protections were only used for multi-
               | bytecode operations. In practice, whether or not a
               | particular Python operation takes a single bytecode or
               | multiple bytecodes is not something you can just read off
               | from the Python code--you have to either have intimate
               | knowledge of the interpreter 's internals or you have to
               | explicitly disassemble each piece of code and look at the
               | bytecode that is generated. Of course the vast majority
               | of programmers don't do that, they just use thread safety
               | protections for every data mutation, which will work
               | without the GIL as well as with it.)
        
               | pdonis wrote:
               | _> if the GIL didn 't prevent races, it would be
               | trivially removable_
               | 
               | Nobody is saying the GIL doesn't prevent races at all. We
               | are saying that the GIL does not prevent races _in your
               | Python code_. It 's not "trivially removable" because it
               | _does_ prevent races in the interpreter 's internal data
               | structures and in operations that are done in a single
               | Python bytecode, and there are a lot of possible races in
               | those places.
               | 
               | Also, perhaps you haven't considered the fact that Python
               | provides tools such as mutexes, locks, and semaphores to
               | help you prevent races in your Python code. Python
               | programmers who do write multi-threaded Python code (for
               | example, code where threads spend most of their time
               | waiting on I/O, which releases the GIL and allows other
               | threads to run) do have to use these tools. Why? Because
               | the GIL by itself does not prevent races in your Python
               | code. You have to do it, just as you do with multi-
               | threaded code in any language.
               | 
               |  _> Races that are already there in people 's Python code
               | have probably been debugged_
               | 
               | Um, no, they haven't, because they've never been exposed
               | to multi-threading. Most people's Python code is not
               | written to be thread-safe, so it can't safely be
               | parallelized as it is, GIL or no GIL.
        
               | d0mine wrote:
               | It is not about your code, it is about C extensions you
               | are relying on. Without GIL, you can't even be sure that
               | refcounting works reliably. Bugs in C extensions are
               | always possible. No GIL makes them more likely. Even if
               | you are not the author of C extension, you have to debug
               | the consequences.
        
               | dudus wrote:
               | Does that mean rewriting all the extensions to Rust? Or
               | maybe CPython itself?
               | 
               | Would that be enough to make Python no gill viable?
        
         | 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:
               | JS had an event loop since the start. It's an old concept
               | that Python seems to have lifted, as did Rust. I used
               | Python for a decade and never really liked the way it did
               | threads.
        
               | zo1 wrote:
               | Python's reactor pattern, or event loop as you call it,
               | started with the "Twisted" framework or library. And that
               | was first published in 2003. That's a full 6 years before
               | Node.js was released which I assume was the first time
               | anything event-loopy started happening in the JS world.
               | 
               | I forgot to mention that it came into prominence in the
               | Python world through the Tornado http server library that
               | did the same thing. Slowly over time, more and more
               | language features were added to give native or first-
               | class-citizen support to what a lot of people were doing
               | behind the scenes (in sometimes very contrived abuses of
               | generator functions).
        
               | stavros wrote:
               | I agree, I find Go's way much easier to reason about.
               | It's all just functions.
        
               | 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. Gets worse the
               | more long-running blocking calls there are.
               | 
               | 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.
               | 
               | > _Also, I was originally asking about free
               | threads...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. The fact that you
               | suggested multiprocessing.Pool instead of
               | concurrent_futures.ProcessPoolExecutor and asked about
               | manual pool management feels like it tells me a little
               | bit about where your head is at here wrt Python.
        
               | hot_gril wrote:
               | Basically true in JS too. You're not supposed to do
               | blocking calls in async code. You also can't "await" an
               | async call inside a non-async func, though you could
               | fire-and-forget it.
               | 
               | Right, but how often does a Python program have complex
               | shared state across threads, rather than some simple fan-
               | out-fan-in, and also need to take advantage of multiple
               | cores?
        
               | nilamo wrote:
               | The primary thing that tripped me up about async/await,
               | specifically only in Python, is that the called function
               | does not begin running until you await it. Before that
               | moment, it's just an unstarted generator.
               | 
               | To make background jobs, I've used the class-based
               | version to start a thread, then the magic method that's
               | called on await simply joins the thread. Which is a lot
               | of boilerplate to get a little closer to how async works
               | in (at least) js and c#.
        
               | LegionMammal978 wrote:
               | Rust's version of async/await is the same in that
               | respect, where futures don't do anything until you poll
               | them (e.g., by awaiting them): if you want something to
               | just start right away, you have to call out to the
               | executor you're using, and get it to spawn a new task for
               | it.
               | 
               | Though to be fair, people complain about this in Rust as
               | well. I can't comment much on it myself, since I haven't
               | had any need for concurrent workloads that Rayon (a basic
               | thread-pool library with work stealing) can't handle.
        
               | pests wrote:
               | That is a common split in language design decisions. I
               | think the argument for the python-style where you have to
               | drive it to begin is more useful as you can always just
               | start it immediately but also let's you delay computation
               | or pass it around similar to a Haskell thunk.
        
               | kristjansson wrote:
               | There is also https://docs.python.org/3/library/asyncio-
               | task.html#eager-ta... if you want your task to start on
               | creation.
        
               | 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.
        
               | kristjansson wrote:
               | Ach, I posted before I saw the rest of your thread,
               | apologies.
               | 
               | Totally agree, concurrent.futures strikes a great
               | balance. Enough to get work done, a bit more constrained
               | than threads on their own.
               | 
               | Asyncio is a lot of cud to chew if you just want a
               | background task in an otherwise sync application
        
               | d0mine wrote:
               | Ordinary CPython code releases GIL during blocking I/O.
               | You can do http requests + thread pool in Python.
        
             | j1elo wrote:
             | So, in Rust they had threading since forever and they are
             | now hyped with this new toy called async/await (and all the
             | new problems it brings), while in Python they've had
             | async/await and are now excited to see the possibilities of
             | this new toy called threads (and all its problems). That's
             | funny!
        
               | BugsJustFindMe wrote:
               | Well, Python had threads already. This is just a slightly
               | different form of them behind the scenes.
        
               | dralley wrote:
               | Yes? They have different use cases which they are good
               | at.
        
               | nvy wrote:
               | Being hyped for <feature other languages have had for
               | years> is totally on-brand for the Rust community.
        
               | hot_gril wrote:
               | That sounds more like Golang (generics)
        
               | hot_gril wrote:
               | Python is more so in the same boat as Rust. Python
               | asyncio was relatively recent.
        
             | throwaway81523 wrote:
             | Yeah I've never liked the async stuff. I've used the
             | existing theading library and it's been fine, for those
             | programs that are blocked on i/o most of the time. The GIL
             | hasn't been a problem. Those programs often ran on single
             | core machines anyway. We would have been better off without
             | the GIL in the first place, but we may be in for headaches
             | by removing it now.
        
           | bongodongobob wrote:
           | Same as any other language. Separating UI from calculations
           | is my most common need for it.
        
           | kstrauser wrote:
           | It's hard to say because we've come up with a lot of ways to
           | work around the fact that threaded Python has always sucked.
           | Why? Because there'd been no demand to improve it. Why?
           | Because no one used it. Why? Because it sucked.
           | 
           | I'm looking forward to seeing how people use a Python that
           | can be meaningfully threaded. While It may take a bit to
           | built momentum, I suspect that in a few years there'll be
           | obvious use cases that are widely deployed that no one today
           | has even really considered.
        
             | hot_gril wrote:
             | Maybe a place to look for obvious use cases is in other
             | languages. JS doesn't have threads, but Swift does. The
             | reason I can't think of one is, free threads are most
             | useful for full parallelism that isn't "embarrassingly
             | parallel," otherwise IPC does fine.
             | 
             | So far, I've rarely seen that. Best example I deal with was
             | a networking project with lots of communication across
             | threads, and that one was too performance-sensitive to even
             | use C++, let alone Py. Other things I can think of are OS
             | programming which again has to be C or Rust.
        
               | kstrauser wrote:
               | That's the kind of thing I stumble across all the time.
               | Indexing all the symbols in a codebase:
               | results = Counter()       for file in here.glob('*.py'):
               | symbols = parse(file)           results.update(symbols)
               | 
               | Scanning image metadata:                 for image in
               | here.glob('*.png'):           headers = png.Reader(image)
               | ...
               | 
               | Now that I think about it, most of my use cases involve
               | doing expensive things to all the files in a directory,
               | but in ways where it'd be really sweet if I could do it
               | all in the same process space instead of using a
               | multiprocessing pool (which is otherwise an excellent way
               | to skin that cat).
               | 
               | I've never let that stop me from getting the job done.
               | There's always a way, and if we can't use tool A, then
               | we'll make tool B work. It'll still be nice if it pans
               | out that decent threading is at least an option.
        
               | hot_gril wrote:
               | These are "embarassingly parallel" examples that
               | multiprocessing is ok for, though. There was always the
               | small caveat that you can't pickle a file handle, but it
               | wasn't a real problem. Threads are more useful if you
               | have lots of shared state and mutexes.
               | 
               | I think these examples would also perform well with GIL'd
               | threads, since the actual Python part is just waiting on
               | blocking calls that do the expensive work. But maybe not.
        
               | kstrauser wrote:
               | > Threads are more useful if you have lots of shared
               | state and mutexes.
               | 
               | That's what always kicks me in such things. If the
               | processes are truly completely separable, awesome! It
               | never seems like they are as much as I wish they were.
        
       | 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)
        
         | jeremycarter wrote:
         | Takes what crown? Python is horrifically slow even single
         | threaded. It's by far the slowest and most energy inefficient
         | of the major choices available today.
        
           | pansa2 wrote:
           | Popularity
        
             | pengaru wrote:
             | javascript has entered the chat
        
       | 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?).
        
         | bastawhiz wrote:
         | I think you'd be hard pressed to find a workload where that
         | behavior needs to be generalized to the degree you're talking.
         | 
         | If you're serving HTTP requests, for instance, simply serving
         | each request on its own thread with its own event loop should
         | be sufficient at scale. Multiple requests each with CPU-bound
         | tasks will still saturate the CPUs.
         | 
         | Very little code teeters between CPU-bound and io-bound while
         | also serving few enough requests that you have cores to spare
         | to effectively parallelize _all_ the CPU-bound work. If that 's
         | the case, why do you need the runtime to do this for you? A
         | simple profile would show what's holding up the event loop.
         | 
         | But still, the runtime can't naively parallelize coroutines.
         | Coroutines are expected not to be run in parallel and that code
         | isn't expected to be thread safe. Instead of a gather on
         | futures, your code would have been using a thread pool executor
         | in the first place if you'd gone out of your way to ensure your
         | CPU-bound code was thread safe: the benefits of async/await are
         | mostly lost.
         | 
         | I also don't think an event loop can be shared between two
         | running threads: if you were to parallelize coroutines, those
         | coroutines' spawned coroutines could run in parallel. If you
         | used an async library that isn't thread safe because it expects
         | only one coroutine is executing at a time, you could run into
         | serious bugs.
        
       | 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?
        
       | jmward01 wrote:
       | I know, I know, 'not every story needs to be about ML' but.... I
       | can only imagine how unlocking the GIL will change the nature of
       | ML training and inference. There is so much waste and complexity
       | in passing memory around and coordinating processes. I know that
       | libraries have made it (somewhat) easier and more efficient but I
       | can't wait to see what can be done with things like pytorch when
       | optimized for this.
        
         | ipsum2 wrote:
         | It'll mostly help for debugging and lowering RAM (not VRAM)
         | usage. Otherwise it won't impact ML much.
        
           | jmward01 wrote:
           | Pretty universally I have seen performance improvements in
           | code when complexity is reduced and this could drop
           | complexity considerably. I wouldn't be surprised to see a
           | double digit percent improvement in tokens per sec when an
           | optimized pytorch eventually comes out with this. There may
           | even be hidden gains on GPU memory usage that come out of
           | this as people clean up code and start implementing better
           | tricks because of it.
        
           | imtringued wrote:
           | Yeah, one of the dumbest things about Dataloaders running in
           | a different process is that you are logging into the void.
        
         | veber-alex wrote:
         | huh?
         | 
         | Any python library that cares about performance is written in
         | C/C++/Rust/Fortran and only provides a python interface.
         | 
         | ML will have 0 benefit from this.
        
           | jmward01 wrote:
           | Have you done any multi-gpu training? Generally every GPU
           | gets a process. Coordinating between them and passing around
           | data between them is complex and can easily have performance
           | issues since normal communication between python processes
           | requires some sort of serialization/de-serialization of
           | objects (there are many * here when it comes to GPU
           | training). This has the potential to simplify all of that and
           | remove a lot of inter-process communication which is just
           | pure overhead.
        
           | KeplerBoy wrote:
           | Of course ML will benefit from it. Soon you will be able to
           | run your dataloaders/data preprocessing in different threads
           | which will not starve your GPUs of data.
        
       | farhanhubble wrote:
       | It remains to be seen how many subtle bugs are now introduced by
       | programmers who have never dealt with real multithreading.
        
       | simonw wrote:
       | I got this working on macOS and wrote up some notes on the
       | installation process and a short script I wrote to demonstrate
       | how it differs from non-free-threaded Python:
       | https://til.simonwillison.net/python/trying-free-threaded-py...
        
         | vanous wrote:
         | Thanks for the example and explanations Simon!
        
       | pansa2 wrote:
       | PEP703 explains that with the GIL removed, operations on lists
       | such as `append` remain thread-safe because of the addition of
       | per-list locks.
       | 
       | What about simple operations like incrementing an integer? IIRC
       | this is currently thread-safe because the GIL guarantees each
       | bytecode instruction is executed atomically.
        
         | pansa2 wrote:
         | Ah, `i += 1` isn't currently thread-safe because Python does
         | (LOAD, +=, STORE) as 3 separate bytecode instructions.
         | 
         | I guess the only things that are a single instruction are some
         | modifications to mutable objects, and those are already
         | heavyweight enough that it's OK to add a per-object lock.
        
           | jillesvangurp wrote:
           | That sounds like the kind of thing that a JIT compiler should
           | be optimizing. The problem with threading isn't stuff like
           | this but people doing a lot of silly things like having
           | global mutable state or stateful objects that are being
           | passed around a lot.
           | 
           | I've done quite a bit of stuff with Java and Kotlin in the
           | past quarter century and it's interesting to see how much
           | things have evolved. Early on there were a lot of people
           | doing silly things with threads and overusing the, at the
           | time, not so great language features for that. But a lot of
           | that stuff replaced by better primitives and libraries.
           | 
           | If you look at Kotlin these days, there's very little of that
           | silliness going on. It has no synchronized keyword. Or a
           | volatile keyword, like Java has. But it does have co-routines
           | and co-routine scopes. And some of those scopes may be backed
           | by thread pools (or virtual thread pools on recent JVMs).
           | 
           | Now that python has async, it's probably a good idea to start
           | thinking about some way to add structured concurrency similar
           | to that on top of that. So, you have async stuff and some of
           | that async stuff might happen on different threads. It's a
           | good mental model for dealing with concurrency and
           | parallelism. There's no need to repeat two decades of
           | mistakes that happened in the Java world; you can fast
           | forward to the good stuff without doing that.
        
       | vegabook wrote:
       | Clearly the Python 2 to 3 war was so traumatising (and so badly
       | handled) that the core Python team is too scared to do the
       | obvious thing, and call this Python 4.
       | 
       | This is a big fundamental and (in many cases breaking) change,
       | even if it's "optional".
        
         | blumomo wrote:
         | Did Python as the language change which justified that version
         | bump?
        
       | grandimam wrote:
       | How is the no-gil performance compared to other languages like -
       | javascript (nodejs), go, rust, and even java? If it's bearable
       | then I believe there is enormous value that could be generated
       | instead of spending time porting to other languages.
        
         | pansa2 wrote:
         | No-GIL Python is still interpreted - single-threaded
         | performance is slower that standard Python, which is in turn
         | _much_ slower than the languages you mentioned.
         | 
         | Maybe if you've got an embarrassingly parallel problem, and
         | dozen(s) of cores to spare, you can match the performance of a
         | single-threaded JIT/AOT compiled program.
        
           | vulnbludog wrote:
           | How do companies like Instagram/OpenAI scale with a majority
           | python codebase? Like I just kick it on HN idk much about
           | computers or coding (think high school CS) why wouldn't they
           | migrate can someone explain like I'm five
        
             | pansa2 wrote:
             | Python may well have been the right choice for companies
             | like that when they were starting out, but now they're much
             | bigger, they would be better off with a different language.
             | 
             | However, they simply have too much code to rewrite it all
             | in another language. Hence the attempts recently to
             | fundamentally change Python itself to make it more suitable
             | for large-scale codebases.
             | 
             | <rant>And IMO less suitable for writing small scripts,
             | which is what the majority of Python programmers are
             | actually doing.</rant>
        
             | imtringued wrote:
             | They have tools like Triton that compile a restricted
             | subset to CUDA.
        
       | earthnail wrote:
       | Oh how much this would simplify torch.DataLoader (and its
       | equivalents)...
       | 
       | Really excited about this.
        
       | VagabundoP wrote:
       | Highly recommend the core.py podcast if you're interested in the
       | background, there are a few episodes that focus on the GILectomy:
       | 
       | -Episode 2: Removing the GIL[1]
       | 
       | -Episode 12: A Legit Episode[2]
       | 
       | [1]https://www.youtube.com/watch?v=jHOtyx3PSJQ&list=PLShJCpYUN3..
       | .
       | 
       | [2]https://www.youtube.com/watch?v=IGYxMsHw9iw&list=PLShJCpYUN3..
       | .
        
       | codethief wrote:
       | Yesterday someone presented preliminary benchmarks here at
       | EuroPython 2024, comparing no-GIL to sub-interpreters and to
       | multiprocessing. Upshot: This gon' be good!
        
       ___________________________________________________________________
       (page generated 2024-07-13 23:00 UTC)