News for hackers. Stuff that matters.
Re:Progress on No-GIL CPython by pdonis on Friday October 20, 2023 @07:49PM (#37962755)
If you have a multi-threaded program with data races, you already have a problem. The GIL does not mean no data races are possible. It just means that only one thread at a time can run Python bytecode. But the interpreter with the GIL can switch threads between bytecodes, and many Python operations, including built-in methods on built-in types that many people think of as "atomic", require multiple bytecodes. That's why Python already provides you with things like locks, mutexes, and semaphores, even though it currently has the GIL.
Re:Progress on No-GIL CPython by rtpg on Friday October 20, 2023 @10:07PM (#37963455)
To put a finer point on this, I’ve had the misunderstanding in the past that the GIL made Python like JavaScript in some sense (only releasing the GIL on some explicit parts of code like sleep). But really Python threads can switch in the “middle” of your code. The reason the GIL is annoying is mostly performance related for Python code itself.

My understanding is the GIL does not protect against Python-side bugs, and bugs from GIL removal would only be introduced from C extensions.

Re:Progress on No-GIL CPython by wokwokwok on Friday October 20, 2023 @11:15PM (#37963785)
? Why do you think this?

This has been discussed extensively in the past (1), and my understanding of the take away was that the GIL doesn't protect you from arbitrary execution order; it protects you from undefined behavior due to concurrent write/read in parallel scopes and the resulting data corruption.

...which, as I understand it, there is no specific reason it would be restricted to native extensions.

Is there some more detail to the nogil proposal that addresses the type of UB you see in eg. c, with this? (Wouldn't that require that at some level the GIL still exists?)

[1] - https://news.ycombinator.com/item?id=30420579

Re:Progress on No-GIL CPython by rfoo on Saturday October 21, 2023 @02:31AM (#37964589)
What you said is precisely what nogil work is about. It's about replacing one global lock with finer grained synchronization primitives without much performance regression.
Re:Progress on No-GIL CPython by pdonis on Saturday October 21, 2023 @10:58PM (#37972448)
> It's about replacing one global lock with finer grained synchronization primitives

Not really, no. The finer grained synchronization primitives are (a) already available in Python, and (b) necessary even with the GIL for reasons I've given elsewhere in this discussion.

What nogil does is enable multiple threads to run Python bytecode at the same time, so that CPU intensive operations in Python can be parallelized without having to use multiple processes. Python objects that are accessed from multiple threads will have to be guarded with synchronization primitives under some circumstances where, in principle, they don't need to be guarded now (operations that only take a single bytecode), but in practice I don't think that will make much difference. The big issue, as has been mentioned elsewhere in this discussion, is C extension modules.

Re:Progress on No-GIL CPython by rfoo on Wednesday October 25, 2023 @04:21PM (#38017809)
> The finer grained synchronization primitives are (a) already available in Python, and (b) necessary even with the GIL for reasons I've given elsewhere in this discussion.

The finer grained synchronization primitives does not already available in Python. Or, it should not be visible to Python code at all. What I'm talking about is the internal implementation of, e.g. PyDict. While from Python bytecode side setitem on it is already not atomic, it does guarantee that Python interpreter won't segfault if there are two Python threads manipulating one dict object concurrently. This is achieved via GIL and has to be replaced.

It's the same problem you mentioned above as "problems in C extension". But no, nogil is hard not only because of compatibility issues. People (especially those who insist on that their workload is inherently embarrassingly parallel) do NOT accept any regression in single-thread performance. If you only ever want to optimize for single thread one global lock is the optimal solution.

Re:Progress on No-GIL CPython by rtpg on Saturday October 21, 2023 @03:53AM (#37964934)
You’re right that the GIL prevents bugs on clobbering exactly the same part of memory in Python. But in the GIL world, a C extensions method that doesn’t release the GIL and doesn’t call into Python has an extra guarantee that it won’t be interrupted at all. This means that in GIL-land, a C extension can have implicit critical sections that stop being so in noGIL land.
Re:Progress on No-GIL CPython by pdonis on Saturday October 21, 2023 @10:14PM (#37972258)
> You’re right that the GIL prevents bugs on clobbering exactly the same part of memory in Python.

No, it doesn't, except for operations that complete in a single byte code. See my response to shrimpx downthread.

Re:Progress on No-GIL CPython by rtpg on Sunday October 22, 2023 @08:51PM (#37980401)
Sorry, I'm being too handwave-y, what I meant (and what i assumed parent meant) is simply that those single bytecode operations are safe thanks to the GIL, so your dictionary or list isn't going to become corrupted because of simultaneous writes.

like l=[], then l.append(1) and l.append(2) running concurrently will not end up in some weird scenario where the length of the list is 1 yet you stored two items... anyways, I agree with the comment you posted higher up in the discussion, and that was my understanding.

Re:Progress on No-GIL CPython by pdonis on Saturday October 21, 2023 @10:15PM (#37972261)
> This has been discussed extensively in the past (1)

Yes, and I weighed in on similar lines in that discussion:

https://news.ycombinator.com/item?id=30423255

Re:Progress on No-GIL CPython by shrimpx on Friday October 20, 2023 @10:49PM (#37963666)
I think by “data races” the parent means that code doesn’t lock around operations like += and len(). The data races are there in theory but do not exhibit due to the GIL.
Re:Progress on No-GIL CPython by pdonis on Saturday October 21, 2023 @10:12PM (#37972250)
But this isn't actually true; that was my point. Neither of these operations, if they are part of an actual statement or expression, will complete in a single byte code. That means that, with the GIL, the operations can be interrupted with a thread switch between bytecodes. So, for example, a statement like

a += b

takes four bytecodes: two LOAD bytecodes to put the values of a and b on the stack, an INPLACE_ADD bytecode to put the result at the top of the stack, and a STORE bytecode to store the result in the variable a. A thread switch could take place in between any two of these bytecodes, and if another thread mutated a or b or was reading the value of a or b, you would have data corruption. The GIL does not prevent this. The only way to prevent it would be to use one of the locking mechanisms provided to guard access to the a and b variables so that only one thread could access them at a time.

Re:Progress on No-GIL CPython by shrimpx on Monday October 23, 2023 @02:19AM (#37982181)
Thank you, I believe you are right. I did try to make a race condition happen using += and am having a hard time. Here's my code

    import threading

    i = 0

    def test():
        global i
        for x in range(1000000):
            i += 1


    threads = [threading.Thread(target=test) for t in range(20)]
    for t in threads:
        t.start()

    for t in threads:
        t.join()

    assert i == 20000000, i
Presumably the assert should fail sometimes but I haven't been able to observe that.
Re:Progress on No-GIL CPython by fulafel on Friday October 20, 2023 @11:47PM (#37963899)
CPython is not really in a good position to change behaviour in incompatible ways and defend it by language lawyering, users expect the same code to mostly work in a backwards compatible way.