comparing the following programs, AtomicInt provides an easy way to achieve correctness, with the nice feature of being lock-free.
using AtomicInt.get_handle() provides great performance improvements.
also see colesbury/nogil#121
$ python
Python 3.9.10 (main, Nov 8 2023, 12:16:13)
[nogil, GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
import threading
class Spam:
def __init__(self):
self.counter = 0
spam = Spam()
print(f"{spam.counter=}")
def incr():
global spam
for _ in range(5_000_000):
spam.counter += 1
threads = [threading.Thread(target=incr) for _ in range(3)]
for t in threads:
t.start()
for t in threads:
t.join()
print(f"{spam.counter=}")
$ /bin/time -p python ./atomic_int_0.py
spam.counter=0
spam.counter=5079663
real 62.42
user 34.62
sys 31.22
$ PYTHONGIL=1 /bin/time -p python ./atomic_int_0.py
spam.counter=0
spam.counter=15000000
real 1.22
user 1.21
sys 0.01
import threading
import cereggii
class Spam:
def __init__(self):
self.counter = cereggii.AtomicInt(0)
spam = Spam()
print(f"{spam.counter.get()=}")
def incr():
global spam
for _ in range(5_000_000):
spam.counter += 1
threads = [threading.Thread(target=incr) for _ in range(3)]
for t in threads:
t.start()
for t in threads:
t.join()
print(f"{spam.counter.get()=}")
$ /bin/time -p python ./atomic_int_1.py
spam.counter.get()=0
spam.counter.get()=15000000
real 56.53
user 26.61
sys 31.90
import threading
import cereggii
class Spam:
def __init__(self):
self.counter = cereggii.AtomicInt(0)
spam = Spam()
print(f"{spam.counter.get()=}")
def incr():
global spam
h = spam.counter.get_handle()
for _ in range(5_000_000):
h += 1
threads = [threading.Thread(target=incr) for _ in range(3)]
for t in threads:
t.start()
for t in threads:
t.join()
print(f"{spam.counter.get()=}")
$ /bin/time -p python ./atomic_int_2.py
spam.counter.get()=0
spam.counter.get()=15000000
real 2.23
user 6.55
sys 0.00
comparing the following programs,
AtomicInt
provides an easy way to achieve correctness, with the nice feature of being lock-free. usingAtomicInt.get_handle()
provides great performance improvements.also see colesbury/nogil#121