线程与线程之间数据是共享的
from threading import Thread def func(lst, name): lst.append(66) print(name, lst) if __name__ == '__main__': lst = [1, 2] t1 = Thread(target=func, args=(lst, "线程1")) t2 = Thread(target=func, args=(lst, "线程2")) t1.start() t2.start() t1.join() t2.join() print("主线程结束", lst)
执行结果:
线程1 [1, 2, 66] 线程2 [1, 2, 66, 66] 主线程结束 [1, 2, 66, 66]
带有global的线程与线程之间的数据共享情况
from threading import Thread def func(name): global n print(f"{name}开始,n={n}") n = 0 print(f"{name}结束,n={n}") if __name__ == '__main__': n = 100 t1 = Thread(target=func, args=("线程1",)) t1.start() t1.join() print(f"主线程结束,n={n}")
执行结果:
线程1开始,n=100 线程1结束,n=0 主线程结束,n=0
接下来看一个由于线程之间的数据是共享而引发问题
from threading import Thread def func(name): print(f"{name}开始") global n for i in range(100000): n += 1 print(f"{name}结束,n={n}") if __name__ == '__main__': n = 0 t1 = Thread(target=func, args=("线程1",)) t2 = Thread(target=func, args=("线程2",)) t1.start() t2.start() t1.join() t2.join() print(f"主线程结束,n={n}")
执行结果:
线程1开始 线程2开始 线程1结束,n=165337 线程2结束,n=147914 主线程结束,n=147914
最终的结果不是我们预期的200000
解决线程与线程之间数据共享导致的问题:加锁
from threading import Thread, Lock def func(name, lock: Lock): # 传递lock,后面添加: Lock表示是Lock类型的,是为了上锁和释放锁的时候会有方法提示功能 print(f"{name}开始") global n for i in range(100000): lock.acquire() # 上锁 n += 1 lock.release() # 释放锁 print(f"{name}结束,n={n}") if __name__ == '__main__': lock = Lock() # 创建一把锁 n = 0 t1 = Thread(target=func, args=("线程1", lock)) t2 = Thread(target=func, args=("线程2", lock)) t1.start() t2.start() t1.join() t2.join() print(f"主线程结束,n={n}")
执行结果:
线程1开始 线程2开始 线程1结束,n=167229 线程2结束,n=200000 主线程结束,n=200000
只看最终结果就行,因为线程1和线程2是并行执行的。
线程与线程之间数据共享(加锁)
from threading import Thread, Lock n = 0 def func(lock, name): lock.acquire() global n for i in range(1000000): n += 1 print("%s拿到了锁" % name) lock.release() if __name__ == '__main__': lock = Lock() # 线程锁 t1 = Thread(target=func, args=(lock, "线程1")) t2 = Thread(target=func, args=(lock, "线程2")) t3 = Thread(target=func, args=(lock, "线程3")) t1.start() t2.start() t3.start() t1.join() t2.join() t3.join() print(n)
运行结果:
线程1拿到了锁
线程2拿到了锁
线程3拿到了锁
3000000
死锁现象
from threading import Thread, Lock def func(name, lock: Lock): # 传递lock,后面添加: Lock表示是Lock类型的,是为了上锁和释放锁的时候会有方法提示功能 print(f"{name}开始") lock.acquire() # 上锁 lock.acquire() # 上锁 print(f"{name}被锁住了") lock.release() # 释放锁 lock.release() # 释放锁 print(f"{name}结束") if __name__ == '__main__': lock = Lock() # 创建一把锁 t1 = Thread(target=func, args=("线程1", lock)) t2 = Thread(target=func, args=("线程2", lock)) t1.start() t2.start() t1.join() t2.join() print(f"主线程结束")
执行结果:
线程1开始
线程2开始
程序一直执行不完,因为程序被锁住了。
解决死锁--->使用递归锁RLock
from threading import Thread, RLock def func(name, lock: RLock): # 传递lock,后面添加: Lock表示是Lock类型的,是为了上锁和释放锁的时候会有方法提示功能 print(f"{name}开始") lock.acquire() # 上锁 lock.acquire() # 上锁 print(f"{name}被锁住了") lock.release() # 释放锁 lock.release() # 释放锁 print(f"{name}结束") if __name__ == '__main__': lock = RLock() # 创建一把锁 t1 = Thread(target=func, args=("线程1", lock)) t2 = Thread(target=func, args=("线程2", lock)) t1.start() t2.start() t1.join() t2.join() print(f"主线程结束")
执行结果:
线程1开始
线程1被锁住了
线程1结束
线程2开始
线程2被锁住了
线程2结束
主线程结束
完美解决死锁的问题,切记锁可以保证数据的安全性,但是效率会降低,相当于把并行改为了串行。
死锁可以想成两个人围着桌子吃饭,两个人的中间各放着一根的筷子,两根筷子在一起才能吃饭,此时,两个人都想吃饭,但是都抓着筷子不放开,结果谁也吃不上饭,就僵死在那了。