多线程共享全局变量时,当多个线程同时对同一共享资源(变量)进行操作(计算)时,可能会出现抢夺资源的情况,从而导致计算结果非预期.
为什么为出现这种情况呢?
如下面这句话:
g_num += 1
看似简单,但是python在执行时,会分成好几步来执行:
step1. 先获取g_num值
step2. 计算g_num = g_num + 1
step3. 赋值给g_num
想想,如果同时有两个或多个线程同时对global变量进行这个操作,当线程1执行到step1后,可能系统资源被线程2抢夺去了,则线程2就会执行step1, 当线程2执行完step3时,g_num已改变,这时系统资源又被线程1给抢走了,而开始计算线程1的step2,则会导致线程1的计算有误,当计算量越大时,其结果就错的越离谱.
所以
线程锁就是为了解决这一问题,锁可以锁定资源,当被锁的资源被操作完成后,再释放资源,这样就保证了资源操作的准确性.
下面三个实例。
1. 多线程同时操作全局变量时计算结果错误。
import threading
from time import sleep
g_num = 0
mutex = threading.Lock()
def addnum1(num):
global g_num
for i in range(1, num):
g_num += 1
print(f'addnum1()::g_num:{g_num}')
def addnum2(num):
global g_num
for i in range(1, num):
g_num += 1
print(f'addnum2()::g_num:{g_num}')
def main():
t1 = threading.Thread(target=addnum1, args=(100001,))
t2 = threading.Thread(target=addnum2, args=(100001,))
t1.start()
t2.start()
sleep(1)
print(f'\n-----------{g_num}-----------')
if __name__ == "__main__":
main()
2. 多线程同时操作全局变量时加锁加在'g_num += 1'前后时,addnum1/addnum2函数总有一个结果不合预期.
import threading
from time import sleep
g_num = 0
mutex = threading.Lock()
def addnum1(num):
global g_num
for i in range(1, num):
mutex.acquire()
g_num += 1
mutex.release()
print(f'addnum1()::g_num:{g_num}')
def addnum2(num):
global g_num
for i in range(1, num):
mutex.acquire()
g_num += 1
mutex.release()
print(f'addnum2()::g_num:{g_num}')
def main():
t1 = threading.Thread(target=addnum1, args=(100001,))
t2 = threading.Thread(target=addnum2, args=(100001,))
t1.start()
t2.start()
sleep(1)
print(f'\n-----------{g_num}-----------')
if __name__ == "__main__":
main()
3. 多线程同时操作全局变量时加锁加在'for'前后时,addnum1/addnum2函数结果完全符合预期.
import threading
from time import sleep
g_num = 0
mutex = threading.Lock()
def addnum1(num):
global g_num
mutex.acquire()
for i in range(1, num):
g_num += 1
mutex.release()
print(f'addnum1()::g_num:{g_num}')
def addnum2(num):
global g_num
mutex.acquire()
for i in range(1, num):
g_num += 1
mutex.release()
print(f'addnum2()::g_num:{g_num}')
def main():
t1 = threading.Thread(target=addnum1, args=(100001,))
t2 = threading.Thread(target=addnum2, args=(100001,))
t1.start()
t2.start()
sleep(1)
print(f'\n-----------{g_num}-----------')
if __name__ == "__main__":
main()
1、2、3值得好好思考,是个好例子.