Answer the question
In order to leave comments, you need to log in
Is the threading.Lock class necessary?
The question is this.
If Python has a GIL that blocks access of different threads to the same memory area, which is actually one of the performance anchors, then why do we need the threading.Lock class, because the threads are already locked by the GIL?
PS
It would probably be cool if someone had articles on this topic lying around
Answer the question
In order to leave comments, you need to log in
Copy and run two different versions of the code.
from threading import *
def work(i):
for _ in range(100):
print(f"hello i'm a thread #{i}")
t1 = Thread(target=work, args=(1,))
t2 = Thread(target=work, args=(2,))
t1.start()
t2.start()
t1.join()
t2.join()
from threading import *
lock = Lock()
def work(i):
for _ in range(100):
with lock:
print(f"hello i'm a thread #{i}")
t1 = Thread(target=work, args=(1,))
t2 = Thread(target=work, args=(2,))
t1.start()
t2.start()
t1.join()
t2.join()
from threading import *
from time import sleep
class GlobalState:
def __init__(self, x):
self.x = x
def set_x(self, x):
self.x = x
def reader(state: GlobalState):
if state.x % 2 == 0:
sleep(0.01) # simulate OS context switch
print(f"{state.x=} is even")
else:
print(f"{state.x=} is odd")
def changer(state: GlobalState):
state.set_x(state.x + 1)
state = GlobalState(2)
t1 = Thread(target=reader, args=(state,))
t2 = Thread(target=changer, args=(state,))
t1.start()
t2.start()
t1.join()
t2.join()
from threading import *
from time import sleep
class GlobalState:
def __init__(self, x):
self.x = x
self.lock = Lock()
def set_x(self, x):
self.x = x
def reader(state: GlobalState):
with state.lock:
if state.x % 2 == 0:
sleep(0.01) # simulate OS context switch
print(f"{state.x=} is even")
else:
print(f"{state.x=} is odd")
def changer(state: GlobalState):
with state.lock:
state.set_x(state.x + 1)
state = GlobalState(2)
t1 = Thread(target=reader, args=(state,))
t2 = Thread(target=changer, args=(state,))
t1.start()
t2.start()
t1.join()
t2.join()
from threading import *
from random import *
class GlobalState:
def __init__(self):
self.x = []
def do_something_changing(self):
if random() < 0.5:
self.x.append(1)
elif self.x:
self.x.pop()
def reader(state: GlobalState):
for _ in range(10000000):
if len(state.x) % 2 == 0:
if len(state.x) % 2 != 0: # wtf how it's possible?
print(f"length {len(state.x)} was even before context switch")
def changer(state: GlobalState):
for _ in range(10000000):
state.do_something_changing()
state = GlobalState()
t1 = Thread(target=reader, args=(state,))
t2 = Thread(target=changer, args=(state,))
t1.start()
t2.start()
t1.join()
t2.join()
GIL which blocks access of different threads to the same memory areaNo, the GIL guarantees that only one thread is running at a time. At the same time, every few tens/hundreds of processor cycles, running threads replace each other (if there is more than one).
which actually is one of the anchors in performanceA controversial and clumsy statement.
why is the threading.Lock class neededTo allow one thread to work, and to prohibit all others. Because otherwise, switching between threads will happen in general at a random moment in time, namely when the interpreter wants. He, of course, does not worry about the logic hardwired into the code and will not wait for the completion of any specific calculations / reading / writing.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question