11 ms·
The Changing "Guarantees" Given by Python's Global Interpreter Lock
- dfox 3y agoCode that assumes that something is going to be atomic because of the GIL (or any other implementation detail) is simply broken. If you need something to be atomic you should be explicit about that and use mutex or something.
- bheadmaster 3y agoTrue, but when a majority of ecosystem is relying on an implementation detail, that implementation detail becomes de-facto standard.
- darklion 3y agoJust because everybody does something the wrong way doesn’t somehow make it magically correct. One study [1] in the US released in 2020 found almost 90% of people admitted to speeding, but I don’t think anyone would say that speeding is now approved by the authorities and consequence-free. [1] https://www.thezebra.com/resources/research/speeding-car-insurance-rates/ https://www.thezebra.com/resources/research/speeding-car-ins...
- bheadmaster 3y ago> Just because everybody does something the wrong way doesn’t somehow make it magically correct. Depends on the definition of "correct". One way to define "correct" is "as defined by the standard". However, standard serves a purpose - to maintain interoperability between components, so the other, deeper, way to define "correct" is "interoperable with the ecosystem". The official standard can argue that relying on the implementation detail is incorrect because they didn't specify it explicitly, but they would go against the grain of the rest of the ecosystem. Which reminds me of an old joke: An old woman is watching the news. She sees a news report saying there is a car driving in the wrong direction on the highway. So the old woman calls up her husband. Old woman: be careful on the highway dear, there is a crazy driver on the highway driving the wrong way! Husband: It’s not just one car, it’s hundreds of them!
- nerdponx 3y agoLest we forget that Python doesn't even have a language standard. The "standard" is a combination of PEPs, the Python docs, and the CPython implementation. Implementation details are language features, because implementation details are the standard. Python programs that rely on the GIL are not "wrong". Such programs are relying on clearly-documented features of the system that they use. Is it "wrong" to use GCC-specific features in a C program, if you know that you only intend to target GCC?
- usrbinbash 3y ago> Implementation details are language features, because implementation details are the standard. Python programs that rely on the GIL are not "wrong". The problem here is: Implementation details are not guaranteed to be stable. They can change with every release. So if I write code that relies on any particular implementation detail, it may be correct today, and may be wrong two weeks from now, even though I didn't change anything.
- samus 3y agoGCC-specific features are explicitly documented in their manual, and they can and should be used if one is fine with one's program being tied to that compiler. Best example: the Linux kernel. On the other hand, Linux kernel developers have also been burned by GCC changing what it does regarding undefined behavior (the infamous not-so-corner cases of C/C++). They expect GCC to be sort of like an assembler, which does the most straightforward thing in case of ambiguities. Instead, GCC is an optimizing compiler that is expected to deliver high-performance code for general-purpose programs. It treats undefined behavior as opportunities to enact optimizations. What it actually does is also usually documented, but also here different people have different expectations about what that implies. The GIL is an implementation choice that was put in place by Python's developers for simplicity's sake. It is important to be aware of it because it has huge performance implications, but it is unwise to rely on it for semantics. Especially since it has not exactly been a secret that various parties would eventually like it to be removed. Anyways, the GIL has very little to do with Python's semantics. User code is racy with or without the GIL, which is actually the point of TA.
- hardware2win 3y agoNobody says it is correct Just hard as hell to change
- gjvc 3y agoJust because everybody does something the wrong way doesn’t somehow make it magically correct. Hyrum's Law says the opposite: https://www.hyrumslaw.com/ https://www.hyrumslaw.com/ "With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody." Named after some guy called Hyrum who worked / works at Google.
- verteu 3y agoAgreed. It's also the "the first rule of kernel maintenance," according to Linus: https://linuxreviews.org/WE_DO_NOT_BREAK_USERSPACE https://linuxreviews.org/WE_DO_NOT_BREAK_USERSPACE
- marcinzm 3y ago> One study [1] in the US released in 2020 found almost 90% of people admitted to speeding, but I don’t think anyone would say that speeding is now approved by the authorities and consequence-free. I would say jaywalking in NYC is a much better example because breaking the law doesn't kill others except in rare cases. Jaywalking is illegal. It's also not enforced for all intents and purposes. Every attempt to enforce it has led to such loud public outcry that it was stopped.
- HDThoreaun 3y agoSpeeding absolutely is approved by the authorities and consequence free where I live.
- citrin_ru 3y agoIf 90% are speeding on a given highway / road then the speed limit is likely unreasonably low. Traffic accident which could be prevented by a speed limit typically caused by fastest 10% of the speed distribution, not by remaining 90%.
- usrbinbash 3y agoMaybe, but "de-facto" and "actual" are still not the same, and if I write code that relies on them being the same, then I have only myself to blame when my code breaks. e.g.; there are C-compilers that usually zero most allocated structures. That's an implementation detail however, not a feature of C. C doesn't guarantee you zeroed memory anywhere, and code that assumes otherwise is just one compilation away from a desaster.
- samus 3y agoThe vendor might not agree with that and change the implementation detail at their convenience. In absence of a prescriptive standard, a reference could be reasonably trusted, but relying on only sort-of-documented implementation details is a kind of tech debt.
- BiteCode_dev 3y agoThe gil is a feature. Not using a feature that makes sense in our context is counter productive.
- nicolaslem 3y agoThe GIL in an implementation detail of CPython, it's not part of Python the language.
- colanderman 3y agoIt's been a while since I've followed Python closely but last I heard Python-the-language is de facto defined as "whatever CPython does". Has Python since grown a proper language specification?
- formerly_proven 3y agoNo.
- dragonwriter 3y agoPython doesn't have a full specification, but it does have first party documentation that distinguishes between CPython implementation details and language guarantees, in part to support alternative implementations.
- pdonis 3y ago> Python doesn't have a full specification This doesn't count? https://docs.python.org/3/reference/index.html https://docs.python.org/3/reference/index.html
- squeaky-clean 3y agoThe introduction section states that it's not a complete/exact specification. If you're using a Python implementation and have a question, this should answer it. If you're writing a Python implementation and have a question, this may not answer it. > Consequently, if you were coming from Mars and tried to re-implement Python from this document alone, you might have to guess things and in fact you would probably end up implementing quite a different language. On the other hand, if you are using Python and wonder what the precise rules about a particular area of the language are, you should definitely be able to find them here. If you would like to see a more formal definition of the language, maybe you could volunteer your time — or invent a cloning machine :-).
- o11c 3y agoIt depends on what kind of "atomic". Assuming sequential consistency is pretty broken. Assuming acquire/release atomicity is much more reasonable. Assuming "at least relaxed" is outright mandatory.
- blamestross 3y agoMost people and scripts using the GIL to ensure safety likely don't even realize it is necessary. That is the hard part of this type of migration. Decades of code written with the implicit assumption of the GIL for all situations.
- Gabrys1 3y agoI don't think people generally write code to use this or another guarantee of the implementation. They write code, they run it, it seems to work (on my machine) and that's it. Later, the implementation changes in a subtle way (or someone tries to run the code in an incompatible version) and the code stops working. Nothing to do with "relying on GIL". The same may apply to relying on dict key order, timing of things, or anything else. That's why we have race conditions, Docker images, freezing dependencies, "only works in IE", etc. Writing to spec is very rare in my experience. You usually learn the spec once someone tells you your code doesn't work on XYZ.
- mikepurvis 3y agoI dunno about that. There's a lot of Python out there with worker threads dumping their output into a shared "results" dict on the assumption that those insert operations are atomic.
- formerly_proven 3y agoRelying on implementation behavior, even if it’s very visible and hasn’t changed for a few decades, is morally wrong and reprehensible. Only the letter of the standard has any bearing on correct reality.
- HDThoreaun 3y ago> morally wrong That's a wild one
- deleted 3y ago[deleted]
- Kranar 3y agoPython's semantics do not have a standards document or specification. It's based on its reference implementation (CPython) and different variations of Python even have different semantics (Jython, IronPython, PyPy). The library is documented, and the syntax is also documented, but the semantics themselves are not.
- lelanthran 3y agoPython doesn't have a standards document. It has a reference implementation that defines the language. IOW, the python implementation is the standard, and therefore any code that relies on an implementation detail in the reference implementation is, by definition, correct.
- oblvious-earth 3y ago> Python doesn't have a standards document. It has a reference implementation that defines the language. That's not quite strictly true, Python does have a documented "Language Reference": https://docs.python.org/3/reference/index.html https://docs.python.org/3/reference/index.html If there is a contradiction between the Language Reference and CPython then one, or both, of them needs to be updated and it's treated on a case by case basis. If an alternative Python implementation follows the Language Reference but chooses different details outside it, that doesn't stop it from being "Python". Of course practically speaking most alternative implementations are incentivized to closely follow CPython.
- solarkraft 3y agoAnd what about PEPs, which describe (in pretty good detail) what changes will be made?
- samus 3y agoThey describe large-scale changes that usually also lead to changes of implementation details. But their biggest disadvantage is that they are not kept up to date when things change due to later PEPs or smaller-scale changes interfering. After landing, they are of historical value only.
- citrin_ru 3y agoA related xkcd: https://xkcd.com/1172/ https://xkcd.com/1172/ For a sufficiently popular project there are often cases where users (other projects) rely on existing observed behavior even if it not guaranteed by documentation/specification.
- hyperpape 3y agoYou can say it's broken until you're blue in the face, and honestly, you're not wrong, but it's irrelevant. If major libraries and user code are constantly incorrect, but work because of an implementation detail, then removing that implementation detail becomes extraordinarily difficult, verging on impossible. It would be like retrofitting your language to distinguish valid unicode text from arbitrary byte strings, when you'd previously treated them as equivalent.
- coldcode 3y agoWhy does Python use an un-comparable version number scheme? Not being a Python programmer, comparing version 3.9 to 3.13 seemed bizarre until I caught on.
- BiteCode_dev 3y agoSem ver is pretty standard imo.
- Scarblac 3y agoLike in most versioning schemes, the dot isn't meant to be read as decimal point.
- rcxdude 3y agocomparing version numbers as tuples and not as decimals is a pretty standard thing. Linux does it as well, for example. I am actually not sure of a project which does something different.
- irishsultan 3y agoTeX and Metafont have version numbers that are approaching pi and e respectively, so the sensible way is to read these as decimals.
- throwaway468234 3y agoIs there any versioning scheme that is comparable? Honest question.
- zzzeek 3y agothese examples of "what one would assume to be atomic" did not seem useful to me, they looked like things that are obviously not threadsafe. a more interesting example is something like this: # setup l = [] # thread A l.extend([1, 2, 3]) # thread B l.extend([4, 5, 6]) is the resulting list always within the set of [1,2,3,4,5,6] or [4,5,6,1,2,3] ? or are the two sets of numbers randomly interleaved in the list? or if the GIL is removed does the interpreter segfault (I'm pretty sure this latter will not be the case for GIL removal but I don't understand the gil remove plan very much yet). Edit: before people jump in and correct how the above is a bad idea anyway, it's not like I'd ever do the above and expect anything but disaster. This is more of a thought experiment to understand what GIL removal is going to do.
- ngoldbaum 3y agoIt’ll be guarded by a fine-grained mutex, so it won’t seg fault. They’re using a performant mutex based on webkit’s wtf::lock.
- OskarS 3y agoI'm guessing interleaving is probably not possible because the `extend` call is passed the full list, and it holds the GIL until it's finished. But you'd have to look at the bytecode to be sure, I suppose. If there were three append calls instead of a single extend, I would assume any interleaving would be valid. > or if the GIL is removed does the interpreter segfault (I'm pretty sure this latter will not be the case for GIL removal but I don't understand the gil remove plan very much yet). I haven't looked into the plan in detail either, but presumably not, that would be nuts. My understanding is that they're going to replace the GIL with locks on the objects themselves (your list `l` in this case). This is why in all the tests single-threaded performance suffer, you have to take and release more locks if you don't have a GIL, and the objects themselves grow larger as well.
- Gabrys1 3y agoLet's say you're passing 1 million ints to each extend. One may start wondering if those operations are then split into chunks...
- continuitylimit 3y agoThe brief blurb about how GIL came to be, in light of Python’s success as a language and a tool, makes me question my s/e belief system. Things like this are like when good things happen to bad people and bad things happen to good people. It makes you question the meaning of it all. Is there no great architect in the sky? Is there no software god after all, looking down, punishing sloppy engineers and granting blessings to thoughtful engineers? How else to explain this injustice of sloppy engineering eating the world (to say nothing of JavaScript)?
- wetpaws 3y ago[dead]
- nerdponx 3y agoOf course there isn't. Software is developed by people. But consider that maybe it wasn't a sloppy design at all. For decades, the explicitly stated philosophy of the CPython development team was to prioritize simplicity of implementation over performance. I don't think anyone ever envisioned Python becoming the wild success that it is today. That is, the GIL wasn't sloppy at all. It was perfectly reasonable and pragmatic decision that made sense given the tradeoffs of the time.
- mrkeen 3y agoIt's network effects, all the way down. Watch people's commentary here when talking about the good and bad of various technologies. There's no 'bad' tech, just tech with lots of users. Or the tech is good because you can hire for it. Because it has lots of users. Or it has a rich ecosystem, because it has lots of users. Read the advice given by those who tell you to get to market first instead of polishing the tech. We're the users of that tech which went to market unpolished and gathered all the users.
- jerf 3y agoWhile there is some truth in what you are saying, you have a common misunderstanding of the situation. Part of the reason the GIL has proved so difficult to remove is that it is actually a good solution. In fact, there have been multiple largely successful attempts to remove it over time over the entire range of aggressiveness from CPython changes to writing an entire JIT stack (PyPy), but it has never gone in to CPython because it would either ruin all existing 3rd party libraries that used C (which is a lot of them), it would diminish performance for an already-slow language, or as in the case of PyPy, it isn't even a "patch" so much as a new project. Especially when you consider this over the whole of Python's lifespan, which very, very firmly includes many years in which multicore was simply not a thing, followed by some years where it was a thing but it didn't work very well anyhow at the OS level so who cares what Python does with it. It is not as if back when it was put it the choice was either to use a GIL or to correctly write a multithreaded interpreter and fix all the 3rd party libraries at the time for exactly the same cost. The latter option was orders of magnitude more expensive, and harder then than it is now, with better tooling and more collective developer experience. The choice of not using a GIL, rather than being some sort of nirvana that we could just be in if they hadn't chosen poorly 15 years ago, could well have killed the language. We don't really know. I do know that a programming language that just sort of breaks every so often when you use threads and there's absolutely nothing you can do about it from the Python level is not a very appealing proposition and it's hard to know how badly this could have hurt the language. And Python of all the languages now has a well-justified fear of breaking everything and demanding that everyone upgrade. So, to put this in a nutshell, if you believe the GIL is simply bad and should never have been an option, you have a very immature understanding of software engineering, especially in the light of being the leader of a very very large community who will be impacted by your decisions. It may not have been the only choice, but it was a good one, and regardless of what decision was made 15 years ago there would be some consequence to deal with now. No programming language community can be expected to get everything right in 2003 that the people of 2023 will want any more than we can expect any current programming language to be the perfect programming language of 2043 right this second.
- sproketboy 3y ago[dead]
- yoyohello13 3y agoIt seems like in every python discussion I hear people complain about the GIL. I’m happy people are working on removing the GIL, but As a professional python dev for about 5 years now I have literally never had a problem where the GIL was a limiter. Although I just make web apps so maybe I’m not the target audience.
- BorgHunter 3y agoConversely, I've worked on backend, data processing-type applications for most of my career, much of it in Java but some (especially recently) in Python, and the GIL is a huge limiting factor for writing efficient, readable Python code. I've had to write very annoying Python code using the multiprocessing library to get around the GIL, and ultimately it works, but it's ugly and clunky and overall just a pain. And remember, I've written a lot of Java code, so I have a high tolerance for pain! But the JVM's concurrency abstractions are actually kind of a joy to use, even if Java the language isn't. Python is the opposite, so if they can shed the GIL and make multithreading viable in Python without forking new processes, that would be a huge win.
- svara 3y agoIt's just about what kind of code you write. If you write a lot of code that parallelizes over data you will hurt all the time because of the GIL. If you have worker processes that do something on the CPU, and the results need to be collected and processed further in some other process, you now need to pickle the data to copy it around. That can get really slow. I understand a lot of python users don't do that kind of thing, but it's a real problem. I'm happy that the python community seems to be slowly beginning to take this seriously after decades of just claiming the GIL isn't a real issue.
- incomingpain 3y agoHow many other people knew nothing about the GIL. Got to using threading and inevitably found major performance issues that were 100% caused by the GIL? Thusly moving to multiprocessing and dealing with the lack of shared memory issues, with managers. When/if the GIL goes away, good riddence.
- phkahler 3y ago>> I have at least one very concrete example of code that someone assumed to be atomic: request_id = self._next_id self._next_id += 1 To think that is thread safe is just naive. Once you understand the potential problem you can look at the code and ask "why shouldn't this be unsafe?" Since there is nothing explicitly preventing the problem. After reading TFA (lazily I admit) I still don't know why that code is thread-safe with the GIL. Python is fun and often forgiving, but a bunch of people who got lucky (because they were never taught about the hazards) are going to learn some new stuff with no-gil. I think it's a long overdue change and worth the (single thread) performance hit and bug surfacing phase.
- toxik 3y agoIt isn’t threadsafe in current Python.
- taway-20230404 3y agoThat example is not thread-safe _behavior-wise_ under the GIL. The block is composed of several individual operations, and the interpreter can preempt a thread between any one of them. On the other hand, it is safe from a memory-access perspective; the read from `self._next_id` will never dereference a partially-mutated invalid pointer or read a partially-mutated value.
- deleted 3y ago[deleted]
- Joel_Mckay 3y agoPythons threading and GC model has always been problematic on multi-core architectures. It shouldn't be anywhere near time-critical and or low-latency use-cases. Python is functionally the modern BASIC, and included many of the same design trade-offs for usability. Don't get mad, it is true... and we know it. =)
- Asooka 3y agoYet more evidence that removing the GIL really ought to bump the major version to Python 4.