Python 线程同步锁
1.多线程调用资源冲突
例子
1 #__author: Lobin 2 #__date: 2018/1/22 3 import threading 4 import time 5 num=100 6 def add(): 7 global num 8 # num-=1 9 temp=num 10 # print('ok') 11 time.sleep(0.0001) 12 num=temp-1 13 14 thread_list=[] 15 for i in range(100): 16 t=threading.Thread(target=add) 17 t.start() 18 thread_list.append(t) 19 for t in thread_list: 20 t.join() 21 22 print('final num:',num)
解析:
每次执行结果不同,由于time.sleep()使得CPU切换线程执行任务时,可能存在所取的变量的值被后一次调用覆盖的情况
2.同步锁将并行转为串行
例子
1 #__author: Lobin 2 #__date: 2018/1/22 3 import threading 4 import time 5 num=100 6 def add(): 7 global num 8 # num-=1 9 lock.acquire() 10 temp=num 11 # print('ok') 12 time.sleep(0.0001) 13 num=temp-1 14 lock.release() 15 16 thread_list=[] 17 lock=threading.Lock() 18 for i in range(100): 19 t=threading.Thread(target=add) 20 t.start() 21 thread_list.append(t) 22 for t in thread_list: 23 t.join() 24 25 print('final num:',num)
解析:
2.1 lock=threading.Lock()创建一个同步锁
2.2在所要转换的同步代码两端加上lock.acquire() 加锁,lock.release()解锁,在加锁后除非释放锁,其他线程不能访问这个代码
3.死锁
例子
1 #__author: Lobin 2 #__date: 2018/1/22 3 import threading,time 4 5 class myThread(threading.Thread): 6 def doA(self): 7 lockA.acquire() 8 print(self.name,"gotlockA",time.ctime()) 9 time.sleep(3) 10 lockB.acquire() 11 print(self.name,"gotlockB",time.ctime()) 12 lockB.release() 13 lockA.release() 14 15 def doB(self): 16 lockB.acquire() 17 print(self.name,"gotlockB",time.ctime()) 18 time.sleep(2) 19 lockA.acquire() 20 print(self.name,"gotlockA",time.ctime()) 21 lockA.release() 22 lockB.release() 23 def run(self): 24 self.doA() 25 self.doB() 26 if __name__=="__main__": 27 28 lockA=threading.Lock() 29 lockB=threading.Lock() 30 threads=[] 31 for i in range(5): 32 threads.append(myThread()) 33 for t in threads: 34 t.start() 35 for t in threads: 36 t.join()#等待线程结束,后面再讲。
结果为:
1 #Thread-1 gotlockA Mon Jan 22 20:21:53 2018 2 #Thread-1 gotlockB Mon Jan 22 20:21:56 2018 3 #Thread-1 gotlockB Mon Jan 22 20:21:56 2018 4 #Thread-2 gotlockA Mon Jan 22 20:21:56 2018
解析:
当线程1执行完A函数时,锁A和锁B都处于释放状态,线程1执行B函数获得锁B,线程2进入A函数获得A锁,当各自执行到需要对方的锁时,进入死锁状态
4.解决方案:使用递归锁
为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。
RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。
直到一个线程所有的acquire都被release,其他的线程才能获得资源。
例子:
1 #__author: Lobin 2 #__date: 2018/1/22 3 import threading,time 4 5 class myThread(threading.Thread): 6 def doA(self): 7 lock.acquire() 8 print(self.name,"gotlockA",time.ctime()) 9 time.sleep(3) 10 lock.acquire() 11 print(self.name,"gotlockB",time.ctime()) 12 lock.release() 13 lock.release() 14 15 def doB(self): 16 lock.acquire() 17 print(self.name,"gotlockB",time.ctime()) 18 time.sleep(2) 19 lock.acquire() 20 print(self.name,"gotlockA",time.ctime()) 21 lock.release() 22 lock.release() 23 def run(self): 24 self.doA() 25 self.doB() 26 if __name__=="__main__": 27 28 # lockA=threading.Lock() 29 # lockB=threading.Lock() 30 lock=threading.RLock() 31 threads=[] 32 for i in range(5): 33 threads.append(myThread()) 34 for t in threads: 35 t.start() 36 for t in threads: 37 t.join()#等待线程结束
结果:
1 #Thread-1 gotlockA Mon Jan 22 20:27:44 2018 2 #Thread-1 gotlockB Mon Jan 22 20:27:47 2018 3 #Thread-1 gotlockB Mon Jan 22 20:27:47 2018 4 #Thread-1 gotlockA Mon Jan 22 20:27:49 2018 5 #Thread-3 gotlockA Mon Jan 22 20:27:49 2018 6 #Thread-3 gotlockB Mon Jan 22 20:27:52 2018 7 #Thread-3 gotlockB Mon Jan 22 20:27:52 2018 8 #Thread-3 gotlockA Mon Jan 22 20:27:54 2018 9 #Thread-5 gotlockA Mon Jan 22 20:27:54 2018 10 #Thread-5 gotlockB Mon Jan 22 20:27:57 2018 11 #Thread-5 gotlockB Mon Jan 22 20:27:57 2018 12 #Thread-5 gotlockA Mon Jan 22 20:27:59 2018 13 #Thread-4 gotlockA Mon Jan 22 20:27:59 2018 14 #Thread-4 gotlockB Mon Jan 22 20:28:02 2018 15 #Thread-4 gotlockB Mon Jan 22 20:28:02 2018 16 #Thread-4 gotlockA Mon Jan 22 20:28:04 2018 17 #Thread-2 gotlockA Mon Jan 22 20:28:04 2018 18 #Thread-2 gotlockB Mon Jan 22 20:28:07 2018 19 #Thread-2 gotlockB Mon Jan 22 20:28:07 2018 20 #Thread-2 gotlockA Mon Jan 22 20:28:09 2018
浙公网安备 33010602011771号