Python 线程锁
一、线程锁(互斥锁Mutex)
1、一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,此时,如果2个线程同时要修改同一份数据,会出现什么状况?
#!/usr/bin/python # -*- coding : utf-8 -*- # 作者: Presley # 时间: 2018-11-20 # 邮箱:1209989516@qq.com # 这是我用来练习python线程锁的测试脚本 import threading import time def addNum(): global num #在每个线程中都获取这个全局变量 print("--get num:",num) time.sleep(1) num -= 1 #对此公共变量进行-1操作 num = 100 #设定一个共享变量 thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: #等待所有线程执行完毕 t.join() print("final num:",num)
结果:python2中每次结果都会不一样,python3中结果都是0
... --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 final num: 0
2、加锁后
#!/usr/bin/python # -*- coding : utf-8 -*- # 作者: Presley # 时间: 2018-11-20 # 邮箱:1209989516@qq.com # 这是我用来练习python线程锁的测试脚本 import threading import time def addNum(): global num #在每个线程中都获取这个全局变量 print("--get num:",num) time.sleep(1) lock.acquire() #获取一把锁 #加锁后相当于变成串行的了 num -= 1 #对此公共变量进行-1操作 lock.release() #必须释放,不施放所有的都等待了 lock = threading.Lock() #定义一个锁实例 num = 100 #设定一个共享变量 thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: #等待所有线程执行完毕 t.join() print("final num:",num)
结果:
... --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 --get num: 100 final num: 0
二、递归锁(RLock)
1、说白了就是在一把大锁中还要再包含子锁。
#!/usr/bin/python # -*- coding : utf-8 -*- # 作者: Presley # 时间: 2018-11-21 # 邮箱:1209989516@qq.com # 这是我用来练习python线程锁的测试脚本 import threading import time def run1(): print("grab the first part data") lock.acquire() global num num += 1 lock.release() return num def run2(): print("grab the second part data") lock.acquire() global num2 num2 += 1 lock.release() return num2 def run3(): lock.acquire() #之所以在执行run1和run2之间加一把锁是因为确保两个方法一块运行完毕 res = run1() print("-------between run1 and run2-----------") res2 = run2() lock.release() print(res,res2) if __name__ == "__main__": num,num2 = 0,0 lock = threading.RLock() for i in range(10): t = threading.Thread(target=run3) t.start() while threading.active_count() != 1: #现在还有几个线程,如果等于1表示只有主线程了,否则表示还没有执行完 print(threading.active_count()) else: print("--all threads done--") print(num,num2)
执行结果:
grab the first part data -------between run1 and run2----------- grab the second part data 1 1 grab the first part data -------between run1 and run2----------- grab the second part data 2 2 grab the first part data -------between run1 and run2----------- grab the second part data 3 3 grab the first part data -------between run1 and run2----------- grab the second part data 4 4 grab the first part data -------between run1 and run2----------- grab the second part data 5 5 grab the first part data -------between run1 and run2----------- grab the second part data 6 6 grab the first part data -------between run1 and run2----------- grab the second part data 7 7 grab the first part data -------between run1 and run2----------- grab the second part data 8 8 grab the first part data -------between run1 and run2----------- grab the second part data 9 9 grab the first part data -------between run1 and run2----------- grab the second part data 10 10 --all threads done-- 10 10
三、信号量(Semaphore)
1、互斥锁,同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据,比如厕所有三个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
#!/usr/bin/python # -*- coding : utf-8 -*- # 作者: Presley # 时间: 2018-11-21 # 邮箱:1209989516@qq.com # 这是我用来练习python线程锁的测试脚本 import threading import time def run(n): semaphore.acquire() time.sleep(1) print("run the thread:%s \n" %n) semaphore.release() if __name__ == "__main__": num = 0 semaphore = threading.BoundedSemaphore(3) #最多允许5个线程同时运行,类似于线程池的概念 for i in range(20): t = threading.Thread(target=run,args=(i,)) t.start()
执行结果:
run the thread:1 run the thread:0 run the thread:2 run the thread:3 run the thread:4 run the thread:5 run the thread:6 run the thread:7 run the thread:8 run the thread:9 run the thread:11 run the thread:10 run the thread:12 run the thread:13 run the thread:14 run the thread:15 run the thread:17 run the thread:16 run the thread:18 run the thread:19