My understanding is that the GIL has lasted this long not because multi-threaded Python depends on it, but because removing it:
- Complicates the implementation of the interpreter
- Complicates C extensions, and
- Causes single-threaded code to run slower
Multi-threaded Python code already has to assume that it can be pre-empted on the boundary between any two bytecode instructions. Does free-threaded Python provide the same guarantees, or does it require multi-threaded Python to be written differently, e.g. to use additional locks?
Mostly. Some of the "can be pre-empted on the boundary between any two bytecode instructions" bugs are really hard to hit without free-threading, though. And without free-threading people don't use as much threading stuff. So by nature it exposes more bugs.
Now, my rants:
> have any other effects on multi-threaded Python code
It stops people from using multi-process workarounds. Hence, it simplifies user-code. IMO totally worth it to make the interpreter more complex.
> Complicates C extensions
The alternative (sub-interpreters) complicates C extensions more than free-threading and the top one most important C extension in the entire ecosystem, numpy, stated that they can't and they don't want to support sub-interpreters. On contrary, they already support free-threading today and are actively sorting out remaining bugs.
> Causes single-threaded code to run slower
That's the trade-off. Personally I think a single digit percentage slow-down of single-threaded code worth it.
Maybe. I would expect that 99% of python code going forward will still be single threaded. You just don’t need that extra complexity for most code. So I would expect that python code as a whole will have worse performance, even though a handful of applications will get faster.
And if there's a good free-threaded HTTP server implementation, the RPS of "Python code as a whole" could increase dramatically.
free-threaded makes sense if you need shared state.
Is it because Rust is just fast? Nope. For anything after resolving dependency versions raw CPU performance doesn't matter at all. It's writing concurrent PLUS parallel code in Rust is easier, doesn't need to spawn a few processes and wait for the interpreter to start in each, doesn't need to serialize whatever shit you want to run constantly. So, someone did it!
Yet, there's a pip maintainer who actively sabotages free-threading work. Nice.
Wow. Could you elaborate?
A 1% slowdown seems totally fine. A 9% slowdown is pretty bad.
How are 'concurrent.futures' users impacted? What will I need to change moving forward?
Things they won't tell you at PyCon.
It's a big project that's going to take lots of time by lots of people to finish. Keep it behind opt-in, keep accepting pull requests after rigorous testing, and it's fine.
https://www.linkedin.com/posts/mdboom_its-been-a-tough-coupl...
Lets see whatever performance improvements still land on CPython, unless other company sponsors the work.
I guess Facebook (no need to correct me on the name) is still sponsoring part of it.
A few decades ago MS did indeed have a playbook which they used to undermine open standards. Laying off some members of the Python team bears no resemblence whatsoever to that. At worst it will delay the improvement of free-threaded Python. That's all.
Your comment is lazy and unfounded.
* VSCode got popular and they started preventing forks from installing its extensions.
* They extended the Free Source pyright language server into the proprietary pylance. They don’t even sell it. It’s just there to make the FOSS version less useful.
* They bought GitHub and started rate limiting it to unlogged in visitors.
Every time Microsoft touches a thing, they end up locking it down. They can’t help it. It’s their nature. And if you’re the frog carrying that scorpion across the pond and it stings you, well, you can only blame it so much. You knew this when they offered the deal.
Every time. It hasn’t changed substantially since they declared that Linux is cancer, except to be more subtle in their attacks.
There's a part of me that wants to scream at them:
"Look around you!!! It's not 1999 anymore!!! These days we have Google, Amazon, Apple, Facebook, etc, which are just as bad if not worse!!! Cut it out with the 20+ year old bad jokes!!!"
Yes, Microsoft is bad. The reason Micr$oft was the enemy back in the day is because they... won. They were bigger than anyone else in the fields that mattered (except for server-side, where they almost one). Now they're just 1 in a gang of evils. There's nothing special about them anymore. I'm more scared of Apple and Google.
But the thing is that Microsoft hasn’t seemed to fundamentally change since 1999. They appear kinder and friendlier but they keep running the same EEE playbook everywhere they can. Lots of us give them a free pass because they let us run a nifty free-for-now programming editor. That doesn’t change the leopard’s spots, though.
MS has continued to metastasize and is in some ways worse than the old days, even if they’ve finally accepted the utility of open source as a loss leader.
They have the only BigTech products I’ve been forced to use if I want to eat.
I’m not anti-MS as much as anti their behavior, whoever is acting that way. This thread is directly related to MS so I’m expressing my opinion on MS here. I’ll be more than happy to share my thoughts on Chrome in a Google thread.
Sabotaging forks is scummy, but the forks were extending MS functionality, not the other way around.
GitHub was a private company before it was bought by MS. Rate limiting is.... not great, but certainly not an extinguish play.
EEE refers to the subversion of open standards or independent free software projects. It does not apply to any of the above.
MS are still scummy but at least attack them on their own demerits, and don't parrot some schtick from decades ago.
So even without EEE, I think it’s supremely risky to hitch your wagon to their tech or services (unless you’re writing primarily for Windows, which is what they’d love to help you migrate to). And I can’t be convinced the GitHub acquisition wasn’t some combination of these dark patterns.
Step 1: Get a plurality of the world’s FOSS into one place.
Step 2: Feed it into a LLM and then embed it in a popular free editor so that everyone can use GPL code without actually having to abide the license.
Step 3: Make it increasingly hard to use for FOSS development by starting to add barriers a little at a time. <= we are here
As a developer, they’ve done nothing substantial to earn my trust. I think a lot of Microsoft employees are good people who don’t subscribe to all this and who want to do the right thing, but corporate culture just won’t let that be.
OK, finally, yes, this is very true, for specific parts of their tech.
But banging on about EEE just distracts from this, more important message.
> Make it increasingly hard to use for FOSS development by starting to add barriers a little at a time. <= we are here
....and now you've lost me again
Hanlon’s razor is a thing, and I generally follow it. It’s just that I’ve seen Microsoft make so many “oops, our bad!” mistakes over the years that purely coincidentally gave them an edge up over their competition, that I tend to distrust such claims from them.
I don’t feel that way about all corps. Oracle doesn’t make little mistakes that accidentally harm the competition while helping themselves. No, they’ll look you in the eye and explain that they’re mugging you while they take your wallet. It’s kind of refreshingly honest in its own way.
Fucking hell bud :D
A classic example is ActiveX.
Nah, even that was based on earlier MS technologies - OLE and COM
A good starter list of EEE plays is on the wikipedia page: https://en.wikipedia.org/wiki/Embrace,_extend,_and_extinguis...
> Examples by Microsoft
> Browser incompatibilities
> The plaintiffs in an antitrust case claimed Microsoft had added support for ActiveX controls in the Internet Explorer Web browser to break compatibility with Netscape Navigator, which used components based on Java and Netscape's own plugin system.
You meant they used ActiveX in an EEE play in the browser wars.
Additionally, at this stage the severe political and governance problems cannot have escaped Microsoft. I imagine that no competent Microsoft employee wants to give his expertise to CPython, only later to suffer group defamation from a couple of elected mediocre people.
CPython is an organization that overpromises, allocates jobs to the obedient and faithful while weeding out competent dissenters.
It wasn't always like that. The issues are entirely self-inflicted.
This stinks of BS
Agreed.
> and communicating across processes often requires making expensive copies of data
SharedMemory [0] exists. Never understood why this isn’t used more frequently. There’s even a ShareableList which does exactly what it sounds like, and is awesome.
[0]: https://docs.python.org/3/library/multiprocessing.shared_mem...
If you want to share structured Python objects between instances, you have to pay the cost of `pickle.dump/pickle.dump` (CPU overhead for interprocess communication) + the memory cost of replicated objects in the processes.
Neither solve the copying problem, though.
I wonder why people never complained so much about JavaScript not having shared-everything threading. Maybe because JavaScript is so much faster that you don't have to reach for it as much. I wish more effort was put into baseline performance for Python.
This is a fair observation.
I think a part of the problem is that the things that make GIL less python hard are also the things that make faster baseline performance hard. I.e. an over reliance of the ecosystem on the shape of the CPython data structures.
What makes python different is that a large percentage of python code isn't python, but C code targeting the CPython api. This isn't true for a lot of other interpreted languages.
Nobody sane tries to do math in JS. Backend JS is recommended for situations where processing is minimal and it is mostly lots of tiny IO requests that need to be shunted around.
I'm a huge JS/Node proponent and if someone says they need to write a backend service that crunches a lot of numbers, I'll recommend choosing a different technology!
For some reason Python peeps keep trying to do actual computations in Python...
Spawning a PYTHON interpreter process might take 30 ms to 300 ms before you get to main(), depending on the number of imports
It's 1 to 2 orders of magnitude difference, so it's worth being precise
This is a fallacy with say CGI. A CGI in C, Rust, or Go works perfectly well.
e.g. sqlite.org runs with a process PER REQUEST - https://news.ycombinator.com/item?id=3036124
It depends on whether one uses clone, fork, posix_spawn etc.
Fork can take a while depending on the size of the address space, number of VMAs etc.
In contrast, no one thinks about what happens if a thread dies independently because the failure mode is joint.
In Rust if a thread holding a mutex dies the mutex becomes poisoned, and trying to acquire it leads to an error that has to be handled. As a consequence every rust developer that touches a mutex has to think about that failure mode. Even if in 95% of cases the best answer is "let's exit when that happens".
The operating system tends to treat your whole process as one and shot down everything or nothing. But a thread can still crash in its own due to unhandled oom, assertion failures or any number of other issues
That's not really true on POSIX. Unless you're doing nutty things with clone(), or you actually have explicit code that calls pthread_exit() or gettid()/pthread_kill(), the whole process is always going to die at the same time.
POSIX signal dispositions are process-wide, the only way e.g. SIGSEGV kills a single thread is if you write an explicit handler which actually does that by hand. Unhandled exceptions usually SIGABRT, which works the same way.
** Just to expand a bit: there is a subtlety in that, while dispositions are process-wide, one individual thread does indeed take the signal. If the signal is handled, only that thread sees -EINTR from a blocking syscall; but if the signal is not handled, the default disposition affects all threads in the process simultaneously no matter which thread is actually signalled.
if you're running in something like AWS fargate, there is no shared memory. have to use the network and file system which adds a lot of latency, way more than spawning a process.
copying processes through fork is a whole different problem.
green threads and an actor model will get you much further in my experience.
Decent threading is awesome news, but it only affects a small minority of use cases. Threads are only strictly necessary when it's prohibitive to message pass. The Python ecosystem these days includes a playbook solution for literally any such case. Considering the multiple major pitfalls of threads (i.e., locking), they are likely to become a thing useful only in specific libraries/domains and not as a general.
Additionally, with all my love to vanilla Python, anyone who needs to squeeze the juice out of their CPU (which is actually memory bandwidth) has a plenty of other tools -- off the shelf libraries written in native code. (Honorable mention to Pypy, numba and such).
Finally, the one dramatic performance innovation in Python has been async programming - I warmly encourage everyone not familiar with it to consider taking a look.
Python has a lot of solid workarounds for avoid threading because until now Python threading has absolutely sucked. I had naively tried to use it to make a CPU-bound workload twice as fast and soon realized the implications of the GIL, so I threw all that code away and made it multiprocessing instead. That sucked in its own way because I had to serialize lots of large data structures to pass around, so 2x the cores got me about 1.5x the speed and a warmer server room.
I would love to have good threading support in Python. It’s not always the right solution, but there are a lot of circumstances where it’d be absolutely peachy, and today we’re faking our way around its absence with whole playbooks of alternative approaches to avoid the elephant in the room.
But yes, use async when it makes sense. It’s a thing of beauty. (Yes, Glyph, we hear the “I told you so!” You were right.)
What's wrong?
Fibers
Green threads
Coroutines
Actors
Queues (eg GCD)
…
Basically you need to reason about what your thing will do.Separate concerns. Each thing is a server (microservice?) with its own backpressure.
They schedule jobs on a queue.
The jobs come with some context, I don’t care if it’s a closure on the heap or a fiber with a stack or whatever. Javascript being single threaded with promises wastefully unwinds the entire stack for each tick instead of saving context. With callbacks you can save context in closures. But even that is pretty fast.
Anyway then you can just load-balance the context across machines. Easiest approach is just to have server affinity for each job. The servers just contain a cache of the data so if the servers fail then their replacements can grab the job from an indexed database. The insertion and the lookup is O(log n) each. And jobs are deleted when done (maybe leaving behind a small log that is compacted) so there are no memory leaks.
Oh yeah and whatever you store durably should be sharded and indexed properly, so practicalkt unlimited amounts can be stored. Availability in a given share is a function of replicating the data, and the economics of it is that the client should pay with credits for every time they access. You can even replicate on demand (like bittorrent re-seeding) to handle spikes.
This is the general framework whether you use Erlang, Go, Python or PHP or whatever. It scales within a company and even across companies (as long as you sign/encrypt payloads cryptographically).
It doesn’t matter so much whether you use php-fpm with threads, or swoole, or the new kid on the block, FrankenPHP. Well, I should say I prefer the shared-nothing architecture of PHP and APC. But in Python, it is the same thing with eg Twisted vs just some SAPI.
You’re welcome.
Python the language is pretty bad. Python the ecosystem of libraries and tools has no equal, unfortunately.
Switching a language is easy. Switching a billion lines of library less so.
And the tragic part is that many of the top “python libraries” are just Python interfaces to a C library! But if you want to switch to a “better language” that fact isn’t helpful.
But changing the language in a brownfield project is hard. I love Go, and these days I don’t bother with Python if I know the backend needs to scale.
But Python’s ecosystem is huge, and for data work, there’s little alternative to it.
With all that said, JavaScript ain’t got shit on any language. The only good thing about it is Google’s runtime, and that has nothing to do with the language. JS doesn’t have true concurrency and is a mess of a language in general. Python is slow, riddled with concurrency problems, but at least it’s a real language created by a guy who knew what he was doing.
AlexanderDhoore•8h ago
DHolzer•8h ago
OFC it would be nice to just write python and everything would be 12x accelerated, but i don't see how there would not be any draw-backs that would interfere with what makes python so approachable.
NortySpock•8h ago
txdv•8h ago
nottorp•7h ago
Considering everyone knew about the GIL, I'm thinking most people just wouldn't bother.
toxik•7h ago
rowanG077•7h ago
immibis•7h ago
kfrane•6h ago
breadwinner•5h ago
jaoane•4h ago
breadwinner•2h ago
jerf•4h ago
I think if someone set out to write a new dynamic scripting language today, from scratch, that multithreading it would not pose any particular challenge. Beyond that fact that it's naturally a difficult problem, I mean, but nothing special compared to the many other languages that have implemented threading. It's all about all that code from before the threading era that's the problem, not the threading itself. And Python has a loooot of that code.
rocqua•3h ago
Multithreaded code is incredibly hard to reason about. And reasoning about it becomes a lot easier if you have certain guarantees (e.g. this argument / return value always has this type, so I can always do this to it). Code written in dynamic languages will more often lack such guarantees, because of the complicated signatures. This makes it even harder to reason about Multithreaded code, increasing the risk posed by multithreaded code.
miohtama•8h ago
immibis•7h ago
rowanG077•7h ago
hamandcheese•6h ago
ynik•4h ago
Even more fun: allocating memory could trigger Python's garbage collector which would also run `__del_-` functions. So every allocation was also a possible (but rare) thread switch.
The GIL was only ever intended to protect Python's internal state (esp. the reference counts themselves); any extension modules assuming that their own state would also be protected were likely already mistaken.
rowanG077•4h ago
> A global interpreter lock (GIL) is used internally to ensure that only one thread runs in the Python VM at a time. In general, Python offers to switch among threads only between bytecode instructions; how frequently it switches can be set via sys.setswitchinterval(). Each bytecode instruction and therefore all the C implementation code reached from each instruction is therefore atomic from the point of view of a Python program.
https://docs.python.org/3/faq/library.html#what-kinds-of-glo...
If this is not the case please let the official python team know their documentation is wrong. It indeed does state that if Py_DECREF is invoked the bets are off. But a ton of operations never do that.
imtringued•6h ago
The only code that is going to break because of "No GIL" are C extensions and for very obvious reasons: You can now call into C code from multiple threads, which wasn't possible before, but is now. Python code could always be called from multiple python threads even in the presence of the GIL in python.
OskarS•5h ago
The problems (as I understand it, happy to be corrected), are mostly two-fold: performance and ecosystem. Using fine-grained locking is potentially much less efficient than using the GIL in the single-threaded case (you have to take and release many more locks, and reference count updates have to be atomic), and many, many C extensions are written under the assumption that the GIL exists.
fulafel•5h ago
kccqzy•5h ago
quectophoton•8h ago
rocqua•3h ago
I wonder if companies will start adding this to their system prompts.
dotancohen•8h ago
cess11•7h ago
https://www.youtube.com/watch?v=_9B__0S21y8 is fairly concise and gives some recommendations for literature and techniques, obviously making an effort in promoting PlusCal/TLA+ along the way but showcases how even apparently simple algorithms can be problematic as well as how deep analysis has to go to get you a guarantee that the execution will be bug free.
dotancohen•7h ago
Of course, while the transcription is in action the rest of the UI (Qt via Pyside) should remain usable. And multiple transcription requests should be supported - I'm thinking of a pool of transcription threads, but I'm uncertain how many to allocate. Half the quantity of CPUs? All the CPUs under 50% load?
Advise welcome!
realreality•7h ago
ptx•1h ago
I don't know how that's done in Pyside, though. I couldn't find a clear example. You might have to use a QThread instead to handle it.
sgarland•6h ago
Use SharedMemory to pass the data back and forth.
HDThoreaun•6h ago
bayindirh•7h ago
With the critical mass Python acquired over the years, GIL becomes a very sore bottleneck in some cases. This is why I decided to learn Go, for example. Properly threaded (and green threaded) programming language which is higher level than C/C++, but lower than Python which allows me to do things which I can't do with Python. Compilation is another reason, but it was secondary with respect to threading.
jillesvangurp•7h ago
What changes for you? Nothing unless you start using threads. You probably weren't using threads anyway because there is little to no point in python to using them. Most python code bases completely ignore the threading module and instead use non blocking IO, async, or similar things. The GIL thing only kicks in if you actually use threads.
If you don't use threads, removing the GIL changes nothing. There's no code that will break. All those C libraries that aren't thread safe are still single threaded, etc. Only if you now start using threads do you need to pay attention.
There's some threaded python code of course that people may have written in python somewhat naively in the hope that it would make things faster that is constantly hitting the GIL and is effectively single threaded. That code now might run a little faster. And probably with more bugs because naive threaded code tends to have those.
But a simple solution to address your fears: simply don't use threads. You'll be fine.
Or learn how to use threads. Because now you finally can and it isn't that hard if you have the right abstractions. I'm sure those will follow in future releases. Structured concurrency is probably high on the agenda of some people in the community.
HDThoreaun•6h ago
Im not worried about new code. Im worried about stuff written 15 years ago by a monkey who had no idea how threads work and just read something on stack overflow that said to use threading. This code will likely break when run post-GIL. I suspect there is actually quite a bit of it.
bgwalter•6h ago
Most C extensions that will break are not written by monkeys, but by conscientious developers that followed best practices.
bayindirh•6h ago
Older code will break, but they break all the time. A language changes how something behaves in a new revision, suddenly 20 year old bedrock tools are getting massively patched to accommodate both new and old behavior.
Is it painful, ugly, unpleasant? Yes, yes and yes. However change is inevitable, because some of the behavior was rooted in inability to do some things with current technology, and as hurdles are cleared, we change how things work.
My father's friend told me that length of a variable's name used to affect compile/link times. Now we can test whether we have memory leaks in Rust. That thing was impossible 15 years ago due to performance of the processors.
delusional•5h ago
No it does not. I hate that analogy so much because it leads to such bad behavior. Software is a digital artifact that can does not degrade. With the right attitude, you'd be able to execute the same binary on new machines for as long as you desired. That is not true of organic matter that actually rots.
The only reason we need to change software is that we trade that off against something else. Instructions are reworked, because chasing the universal Turing machine takes a few sacrifices. If all software has to run on the same hardware, those two artifacts have to have a dialogue about what they need from each other.
If we didnt want the universal machine to do anything new. If we had a valuable product. We could just keep making the machine that executes that product. It never rots.
kstrauser•5h ago
But if you tried to compile it on today’s libc, making today’s syscalls… good luck with that.
Software “rots” in the sense that it has to be updated to run on today’s systems. They’re a moving target. You can still run HyperCard on an emulator, but good luck running it unmodded on a Mac you buy today.
dahcryn•5h ago
If software is implicitly built on wrong understanding, or undefined behaviour, I consider it rotting when it starts to fall apart as those undefined behaviours get defined. We do not need to sacrifice a stable future because of a few 15 year old programs. Let the people who care about the value that those programs bring, manage the update cycle and fix it.
eblume•5h ago
igouy•3h ago
bayindirh•3h ago
When you look from the program's perspective, the context changes and becomes unrecognizable, IOW, it rots.
When you look from the context's perspective, the program changes by not evolving and keeping up with the context, IOW, it rots.
Maybe we anthropomorphize both and say "they grow apart". :)
igouy•1h ago
We say the context is not backwards compatible.
indymike•4h ago
I'm thankful that it does, or I would have been out of work long ago. It's not that the files change (literal rot), it is that hardware, OSes, libraries, and everything else changes. I'm also thankful that we have not stopped innovating on all of the things the software I write depends on. You know, another thing changes - what we are using the software for. The accounting software I wrote in the late 80s... would produce financial reports that were what was expected then, but would not meet modern GAAP requirements.
rocqua•3h ago
Software doesn't rot, it remains constant. But the context around it changes, which means it loses usefulness slowly as time passes.
What is the name for this? You could say 'software becomes anachronistic'. But is there a good verb for that? It certainly seems like something that a lot more than just software experiences. Plenty of real world things that have been perfectly preserved are now much less useful because the context changed. Consider an Oxen-yoke, typewriters, horse-drawn carriages, envelopes, phone switchboards, etc.
It really feels like this concept should have a verb.
igouy•1h ago
cestith•5h ago
spookie•3h ago
I wish more things were like that. Tired of building things on shaky grounds.
actinium226•6h ago
I feel some trepidation about threads, but at least for debugging purposes there's only one process to attach to.
dhruvrajvanshi•1h ago
I was with OP's point but then you lost me. You'll always have to deal with that coworker's shitty code, GIL or not.
Could they make a worse mess with multi threading? Sure. Is their single threaded code as bad anyway because at the end of the day, you can't even begin understand it? Absolutely.
But yeah I think python people don't know what they're asking for. They think GIL less python is gonna give everyone free puppies.
dkarl•5h ago
Coming from the Java world, you don't know what you're missing. Looking inside an application and seeing a bunch of threadpools managed by competing frameworks, debugging timeouts and discovering that tasks are waiting more than a second to get scheduled on the wrong threadpool, tearing your hair out because someone split a tiny sub-10μs bit of computation into two tasks and scheduling the second takes a hundred times longer than the actual work done, adding a library for a trivial bit of functionality and discovering that it spins up yet another threadpool when you initialize it.
(I'm mostly being tongue in cheek here because I know it's nice to have threading when you need it.)
rbanffy•4h ago
A fairly common pattern for me is to start a terminal UI updating thread that redraws the UI every second or so while one or more background threads do their thing. Sometimes, it’s easier to express something with threads and we do it not to make the process faster (we kind of accept it will be a bit slower).
The real enemy is state that can me mutated from more than one place. As long as you know who can change what, threads are not that scary.
zem•7h ago
freeone3000•6h ago
im3w1l•4h ago
bratao•6h ago
amelius•6h ago
pansa2•4h ago
amelius•4h ago
porridgeraisin•5h ago
kevingadd•2h ago
tialaramex•6h ago
In a language conceived for this kind of work it's not as easy as you'd like. In most languages you're going to write nonsense which has no coherent meaning whatsoever. Experiments show that humans can't successfully understand non-trivial programs unless they exhibit Sequential Consistency - that is, they can be understood as if (which is not reality) all the things which happen do happen in some particular order. This is not the reality of how the machine works, for subtle reasons, but without it merely human programmers are like "Eh, no idea, I guess everything is computer?". It's really easy to write concurrent programs which do not satisfy this requirement in most of these languages, you just can't debug them or reason about what they do - a disaster.
As I understand it Python without the GIL will enable more programs that lose SC.
qznc•5h ago
odiroot•5h ago
almostgotcaught•4h ago
"Python programmers are so incompetent that Python succeeds as a language only because it lacks features they wouldn't know to use"
Even if it's circumstantially true, doesn't mean it's the right guiding principle for the design of the language.
frollogaston•2h ago
I don't fully understand the challenge with removing it, but thought it was something about C extensions, not something most users have to directly worry about.