7 ms·
I wonder how many folks think they're writing thread safe software with ease, and are unaware that they are leaning on the GIL? Could be that the impact of thi
by dleslie 5y ago
I wonder how many folks think they're writing thread safe software with ease, and are unaware that they are leaning on the GIL?
Could be that the impact of this change is far broader than just a few key libraries.
- deleted 5y ago[deleted]
- avianlyric 5y agoI don’t see how the GIL makes writing thread safe software any easier. The GIL might prevent two Python threads executing simultaneously, but it doesn’t change the fact that a Python thread can be preempted, meaning your global state can change at any point during execution without warning. Most of the issues with multi-threading come from concurrency, not parallelism. The GIL allows concurrency, you just don’t get any of the advantages of parallelism, which is normally the reason for putting up with the complexity concurrency creates.
- dleslie 5y ago> The GIL might prevent two Python threads executing simultaneously, but it doesn’t change the fact that a Python thread can be preempted, meaning your global state can change at any point during execution without warning. That thread behavior is enough to reduce the likelihood of races and collisions; particularly if the critical sections are narrow.
- laserlight 5y agoI wouldn’t call it thread-safe when race conditions are possible.
- jldugger 5y agoThen we need a term for when code race conditions are possible but rare enough that nobody using the software notices. thread-timebomb?
- phkahler 5y ago>> then we need a term for when code race conditions are possible but rare enough There is no such thing as "rare enough". Random or probabilistic bugs are one of the worst things software can have.
- nuerow 5y ago> Then we need a term for when code race conditions are possible but rare enough that nobody using the software notices. thread-timebomb? There's already a term for that: not thread-safe. The definition of thread safety does not include theoretical or practical assessments regarding how frequent a problem can occurr. It only assesses whether a specific class of problems is eliminated or not.
- jldugger 5y ago>The definition of thread safety does not include theoretical or practical assessments regarding how frequent a problem can occur. Well, obviously. The challenge I am putting forth on HN is to meaningfully describe _usable_ thread-unsafe software. If you've spent enough time outside university, you'll be aware that there are all kinds of theoretical race conditions that are not triggered in practical use.
- klyrs 5y agoIf you've worked at industrial scale, you'll be aware that even the most theoretical-seeming race condition will be triggered frequently.
- Brian_K_White 5y agoThere is no such thing as "likely". A thing is either possible or not possible.
- kingofpandora 5y agoLikelihood refers to probability not possibility.
- Brian_K_White 5y agoThere is no such thing as probability. All there is is possible and not possible. I don't know how the point of the comment could be missed, but what I am saying is, it is a mistake, a rookie baby not-a-programmer not even any kind of engineer in any field, to even think in those sorts of terms at all. At least not in the platonic ideal worlds of math or code or protocol or systems design or legal documents, etc. Physical events have probability that is unavoidable. How fast does the gas burn? "Probably this fast" There is no excuse for any coder to even utter the word "likely". The ONLY answers to "Is this operation atomic?" or "Is this function correct?" or "Does this cpu perform division correctly?" Is either yes or no. There is no freaking "Most of the time." "Likely" only exists in the realm of user data and where it is explicitly created as part of an algorythm.
- yholio 5y agoThere are whole branches of computer science and IT dedicated to reducing the likelihood of unpleasant outcomes: cryptography, security, disaster recovery etc. You cannot guarantee your public key algorithm is impossible to break, but you can use keys long enough that an attacker has an arbitrarily low chance of succes with the best known methods. You cannot prove your program is bug free, outside of highly specialized fields like aircraft control, but you can build a multi-layered architecture that can reduce the likelihood of successful intrusion. You cannot prevent a EMP bomb from wiping all your hard-drives at once, but you will likely maintain integrity of your database for uncorrelated hardware errors. "Likely" is a tool that works in the real world. If you will chase mathematic certainty, your competition will likely eat your lunch. Where you might be correct is that "unlikely" is very close to "likely" in the particular topic of thread safety, you just need a sufficiently large userbase with workloads and environments sufficiently different from your test setup.
- avianlyric 5y agoThat just means the GIL is good at hiding concurrency bugs. It doesn’t make writing correct code any easier. Arguably you could say it makes writing correct concurrent code harder, because it’ll take significantly longer for concurrency bugs cause errors.
- chacham15 5y agoThere are certain classes of errors that it prevents. E.g: Thread1: a = 0xFFFFFFFF00000000 Thread2: a = 0x00000000FFFFFFFF One might think that the two possible values of a if those are run concurrently are 0xFFFFFFFF00000000 and 0x00000000FFFFFFFF. But actually 0x0000000000000000 and 0xFFFFFFFFFFFFFFFF are also possible because the load itself isnt atomic. The GIL (AFAICT) will prevent the latter two possibilities.
- intrepidhero 5y agoBut if you're writing to the same object from two different threads you're going to have undefined behavior regardless of the GIL, yes?
- NovemberWhiskey 5y agoNot really. If you're doing an atomic write to the same object from two different threads, you're going to have one win the race and the other lose. That may be a bug in your code, but it's not undefined behavior at the language level.
- ajkjk 5y agoIt prevents classes of errors, such as, as the parent mentioned, non-atomic writes to individual variables.
- fulafel 5y agoNo. The L in GIL stands for lock. So only the thread that holds it can write or read from the object, and the behavior is well defined at the C level, because C lock acquire and release operations are defined to be memory barriers.
- dkersten 5y agoBut when each thread reads the variable, you have no control over which value you see, since you don't control when each thread gets to run. So its undefined in the sense that you don't know which values you will get: a thread might get the value it wrote, or the value the other thread wrote. The threads might not get the same value either. The GIL exists to protect the interpreters internal data, not your applications data. If you access mutable data from more than one thread, you still need to your own synchronisation.
- dehrmann 5y agoIt's more cpython than the GIL, but it lets you get away with using += and certain dict operations without locks.
- hexane360 5y agoIs this true? It looks like += compiles to four bytecode instructions: two loads, an increment, and a store. It should be possible for a thread to get paused after the load but before the store, resulting in a stale read and lost write. Some more discussion here: https://stackoverflow.com/questions/1717393/is-the-operator-thread-safe-in-python https://stackoverflow.com/questions/1717393/is-the-operator-...
- dehrmann 5y agoMaybe it's just certain collection operations, then.
- detaro 5y agoAnd the proposal clearly addresses adjusting those to maintain the expected guarantees.
- pansa2 5y agoWith the GIL, for an int i, `i += 1` is not thread-safe, but IIRC for a list l, `l += [1]` (i.e. extend) is. Presumably this patch changes the list implementation in some way so that the extend operation remains thread-safe without the GIL.
- stefan_ 5y agoFrom running the same software on two moderately powerful embedded systems, one single-core and one multi-core, the latter is a lot more reliable in immediately exposing races and concurrency issues.
- hyperbovine 5y agoConversely, I have found that the GIL makes it unexpectedly easy to write thread-safe software in Python. Compare (in Cython) writing with gil: call_a_method() print(some_debugging_info) with all the sit-ups you’d have to do in a “real” concurrent language.
- ynik 5y agoThe GIL doesn't really help Python code though, because the interpreter may switch threads between any two opcodes. It only protects the state of the Python interpreter and that of C/Cython extension modules. Though even there, you can have unexpected thread switches, e.g. in Cython `self.obj = None` can result in a thread switch if the value previously stored in `self.obj` had a `__del__` method implemented in Python. And AFAIK pretty much any Python object allocation can trigger the cycle collector which can trigger `__del__` on (completely unrelated) objects in reference cycles, so it's pretty much impossible to rely on the GIL to keep any non-trivial code block atomic.
- rectang 5y agoI have read many anti-GIL arguments over the years that approach soundness as optional. Is this change going to make a bunch of previously sound code unsound?
- jnxx 5y agoI have seen that once in supposedly thread-safe C++ software in an industrial automation application. What happened was that it was somehow relying on the Windows UI messaging system (the message pump) which is single-threaded, and the fact that there were no multi-core CPUs when that stuff was written a long time ago. The latter has the effect that the CPU always sees a consistent view on the memory, no locks, mutexes and barriers needed. Porting the thing to a multi-core system revealed that there were a lot of nasty concurrency bugs, like dead-locks or crashes which happened after a day of operation. And this wasn't a toy system - it was in use for a long time in an industrial application, and the customer was not too happy about the intermittent dead-locks. I commiserated with the poor engineer who had the quite stressful task to debug this, equipped with a lot of dedication but an insufficient background. Frankly, while it would be nice to be able to write parallel code in pure Python, I think that Clojure with its purely-functional approach has the better concepts for this. And moreover, actually improving performance by parallel computation (using several CPUs to work in parallel on the same thing) is damn hard and unsolved in many cases (just come up with an efficient parallel Fast Fourier Transform and you might get a Turing award). What is mostly needed (outside of massive data processing pipelines) is concurrency for event-driven systems. Python can handle that, Clojure does handle it in a much more elegant way.