On 2023-02-26, Chris Angelico <ros...@gmail.com> wrote: > On Sun, 26 Feb 2023 at 16:16, Jon Ribbens via Python-list ><python-list@python.org> wrote: >> On 2023-02-25, Paul Rubin <no.email@nospam.invalid> wrote: >> > The GIL is an evil thing, but it has been around for so long that most >> > of us have gotten used to it, and some user code actually relies on it. >> > For example, with the GIL in place, a statement like "x += 1" is always >> > atomic, I believe. But, I think it is better to not have any shared >> > mutables regardless. >> >> I think it is the case that x += 1 is atomic but foo.x += 1 is not. >> Any replacement for the GIL would have to keep the former at least, >> plus the fact that you can do hundreds of things like list.append(foo) >> which are all effectively atomic. > > The GIL is most assuredly *not* an evil thing. If you think it's so > evil, go ahead and remove it, because we'll clearly be better off > without it, right?
If you say so. I said nothing whatsoever about the GIL being evil. > As it turns out, most GIL-removal attempts have had a fairly nasty > negative effect on performance. The GIL is a huge performance boost. > > As to what is atomic and what is not... it's complicated, as always. > Suppose that x (or foo.x) is a custom type: Yes, sure, you can make x += 1 not work even single-threaded if you make custom types which override basic operations. I'm talking about when you're dealing with simple atomic built-in types such as integers. > Here's the equivalent with just incrementing a global: > >>>> def thrd(): > ... x += 1 > ... >>>> dis.dis(thrd) > 1 0 RESUME 0 > > 2 2 LOAD_FAST_CHECK 0 (x) > 4 LOAD_CONST 1 (1) > 6 BINARY_OP 13 (+=) > 10 STORE_FAST 0 (x) > 12 LOAD_CONST 0 (None) > 14 RETURN_VALUE >>>> > > The exact same sequence: load, add, store. Still not atomic. And yet, it appears that *something* changed between Python 2 and Python 3 such that it *is* atomic: import sys, threading class Foo: x = 0 foo = Foo() y = 0 def thrd(): global y for _ in range(10000): foo.x += 1 y += 1 threads = [threading.Thread(target=thrd) for _ in range(50)] for t in threads: t.start() for t in threads: t.join() print(sys.version) print(foo.x, y) 2.7.5 (default, Jun 28 2022, 15:30:04) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] (64489, 59854) 3.8.10 (default, Nov 14 2022, 12:59:47) [GCC 9.4.0] 500000 500000 -- https://mail.python.org/mailman/listinfo/python-list