线程锁
为什么会有线程锁,首先这里说一个例子
假设我的计算机的CPU略微拉跨一点,然后我有个三个线程进行计算,同时计算量都不小,这时候就有可能出现算错的情况
具体代码如下
from threading import Thread
x = 0
def task():
global x
for i in range(2000000000):
x += 1
if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task)
t3 = Thread(target=task)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(x)
这个代码里面启动了三个子线程,然后这三个子进程都运行函数里面的相加,同时每次都会修改全局里面x的值。
会出现计算错误的情况
结果如下

这里的结果就出现错误了,为什么会这样呢?因为它在运行时t1时,t2和t3也在运行这就会出现抢CPU的情况了,然后t1运行好了,t2就抢走了然后它运行后又把t1的定义x的值给打乱了,但是这时候t3也会来抢CPU这就会导致x的值出现误差,这就是多线程经常出现的BUG。
上面的也可以这么理解:就是有三个软件都是来杀病毒软件的,然后软件A抢先一步来杀病毒软件,就在杀毒快完成准备保存正确的结果时,软件B反应了过来抢这个病毒软件进行杀毒,导致软件A的杀毒没有彻底完成,软件B也是快杀完毒准备保存时,软件C当老六抢走了这个病毒软件进行杀毒,软件B也是没有彻底完成。这就会造成软件A又去抢,抢完软件B又来抢,再然后软件C又来抢。
最后的结果就会是病毒没杀掉,电脑先崩了,赔了软件又赔了电脑血亏。
所以这就是为什么要有线程锁这个情况,就是为了防止这个情况
下面用进程锁解决这个问题
首先还是与进程锁用同一个模块Lock
然后再定义一把锁
在主要的函数里面给核心计算功能上锁
当主要功能运行完后再解锁
代码如下
from threading import Thread, Lock
x = 0
suo = Lock() # 生成一把锁
def task():
suo.acquire() # 这里上锁
global x
for i in range(200000):
x += 1
suo.release() # 上面的运行完了再把锁给解了
if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task)
t3 = Thread(target=task)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(x)
然后结果为

这个结果就体现了线程锁的用法,先给主要的计算功能上锁,哪个线程抢到了它独用此方法,其它的线程只能等它用完了并且解锁了才能使用,这就预防了线程与线程之间出现抢CPU的情况了。
还有一种便捷的格式来实现上锁以及释放锁的功能
代码如下
from threading import Thread, Lock
x = 0
suo = Lock() # 生成一把锁
def task():
with suo: # 这里将上锁以及释放锁的方法给隐式的发生在with suo 换句话就是这里面包含了上锁和释放锁的方式
global x
for i in range(2000000000):
x += 1
if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task)
t3 = Thread(target=task)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(x)
这个代码里面让with上下文管理器与锁对象一起使用,提供了一种方便的方式来实现锁的上锁和解锁,这样做会让代码更加清晰,同时防止了忘记释放锁的可能。
with是如何实现的呢?
因为我给这个锁命名的是suo,然后with和它一起使用就能隐式(不会显示)的调用suo对象里面的 _ _ enter _ _ 方法和 _ _ exit _ _ 方法,这样就实现了上锁和释放锁的功能了
修改比喻
这里将上述的比喻修改一下
多个软件(线程)试图同时访问和修改共享资源,例如病毒软件,而没有适当的同步机制。软件A率先访问病毒软件,但在完成清除病毒任务之前,软件B也开始争抢同一个资源。之后,软件C也可能加入竞争。
这种情况下,没有足够的协调和同步,不同的软件之间会竞争共享资源,导致不确定的行为,例如清除任务可能不完整。为了解决这个问题,需要使用同步机制,如锁,以确保一次只有一个软件能够成功访问共享资源,从而避免竞态条件,确保任务以有序的方式执行。