1.多线程调用资源冲突
例子
1 #__author: Lobin
2 #__date: 2018/1/22
3 importthreading4 importtime5 num=100
6 defadd():7 globalnum8 #num-=1
9 temp=num10 #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 inthread_list:20 t.join()21
22 print('final num:',num)
解析:
每次执行结果不同,由于time.sleep()使得CPU切换线程执行任务时,可能存在所取的变量的值被后一次调用覆盖的情况
2.同步锁将并行转为串行
例子
1 #__author: Lobin
2 #__date: 2018/1/22
3 importthreading4 importtime5 num=100
6 defadd():7 globalnum8 #num-=1
9 lock.acquire()10 temp=num11 #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 inthread_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 importthreading,time4
5 classmyThread(threading.Thread):6 defdoA(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 defdoB(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 defrun(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 inthreads:34 t.start()35 for t inthreads: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 importthreading,time4
5 classmyThread(threading.Thread):6 defdoA(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 defdoB(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 defrun(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 inthreads:35 t.start()36 for t inthreads: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