Python3 从零单排27_锁&信号量&Event&定时器
1.死锁
是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
1 from threading import Thread,Lock 2 import time 3 4 mutexA=Lock() 5 mutexB=Lock() 6 7 class MyThread(Thread): 8 def run(self): 9 self.f1() 10 self.f2() 11 12 def f1(self): 13 mutexA.acquire() 14 print('%s 拿到了A锁' % self.name) 15 mutexB.acquire() 16 print('%s 拿到了B锁' % self.name) 17 mutexB.release() 18 print('%s 释放了B锁' % self.name) 19 mutexA.release() 20 print('%s 释放了A锁' % self.name) 21 22 def f2(self): 23 mutexB.acquire() 24 print('%s 拿到了B锁' % self.name) 25 time.sleep(0.1) 26 mutexA.acquire() 27 print('%s 拿到了A锁' % self.name) 28 mutexA.release() 29 print('%s 释放了A锁' % self.name) 30 mutexB.release() 31 print('%s 释放了B锁' % self.name) 32 33 if __name__ == '__main__': 34 for i in range(10): 35 t=MyThread() 36 t.start()
2.递归锁
互斥锁只能acquire一次
递归锁:可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire
1 # 互斥锁只能acquire一次 2 from threading import Thread,Lock 3 4 mutexA=Lock() 5 6 mutexA.acquire() 7 mutexA.acquire() # 程序卡在这里了 8 9 10 # 递归锁:可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire 11 from threading import Thread,RLock 12 import time 13 14 mutexB=mutexA=RLock() 15 16 class MyThread(Thread): 17 def run(self): 18 self.f1() 19 self.f2() 20 21 def f1(self): 22 mutexA.acquire() 23 print('%s 拿到了A锁' % self.name) 24 mutexB.acquire() 25 print('%s 拿到了B锁' % self.name) 26 mutexB.release() 27 print('%s 释放了B锁' % self.name) 28 mutexA.release() 29 print('%s 释放了A锁' % self.name) 30 31 def f2(self): 32 mutexB.acquire() 33 print('%s 拿到了B锁' % self.name) 34 time.sleep(0.1) 35 mutexA.acquire() 36 print('%s 拿到了A锁' % self.name) 37 mutexA.release() 38 print('%s 释放了A锁' % self.name) 39 mutexB.release() 40 print('%s 释放了B锁' % self.name) 41 42 if __name__ == '__main__': 43 for i in range(10): 44 t=MyThread() 45 t.start()
3.信号量
互斥锁或者递归锁都只能在一个时间点为同一个线程服务,一个萝卜一个坑。但是多个萝卜可以同时占用多个坑就没办法了,这里就用到了信号量。
信号量,体现在量,批量,也就是说支持同一时间点可以给多个线程用,原理实际是计数器,占用一个-1,释放一个+1,计数不能小于0。
Semaphore管理一个内置的计数器,每当调用acquire()时内置计数器-1;调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。
1 from threading import Thread, Semaphore, current_thread 2 import time, random 3 se = Semaphore(3) # 最多只能同时占用3次 4 5 6 def toilet(): 7 with se: # 用法同文件操作,将打开和关闭合并在with语法里。 等价于 se.acquire() se.release() 8 print("%s go in" % current_thread().getName()) 9 time.sleep(random.randint(1, 3)) 10 11 12 if __name__ == "__main__": 13 for i in range(10): 14 t = Thread(target=toilet) 15 t.start()
4.Event
线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。
为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。
在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。
一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行
event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
1 from threading import Thread, Event 2 import time 3 e = Event() 4 5 def student(name): 6 print("%s is learning" % name) 7 e.wait(3) # 一直等event.set(),最多等3秒 8 print("%s is playing" % name) 9 10 def teacher(name): 11 print("%s is teaching" % name) 12 time.sleep(6) 13 print("%s said class over!" % name) 14 e.set() 15 16 17 if __name__ == "__main__": 18 for i in range(10): 19 s = Thread(target=student, args=(i,)) 20 s.start() 21 t = Thread(target=teacher) 22 t.start()
5.定时器 定时执行任务
1 from threading import Timer 2 3 4 def toilet(name): 5 print("%s go in" % name) 6 7 8 if __name__ == "__main__": 9 for i in range(10): 10 t = Timer(3, toilet, args=("xg %s" % i,)) # 3秒后 启动toilet 11 t.start() 12 13 14 from threading import Timer 15 import random 16 17 class Code: 18 def __init__(self): 19 self.make_cache() 20 21 def make_cache(self,interval=5): 22 self.cache=self.make_code() 23 print(self.cache) 24 self.t=Timer(interval,self.make_cache) 25 self.t.start() 26 27 def make_code(self,n=4): 28 res='' 29 for i in range(n): 30 s1=str(random.randint(0,9)) 31 s2=chr(random.randint(65,90)) 32 res+=random.choice([s1,s2]) 33 return res 34 35 def check(self): 36 while True: 37 code=input('请输入你的验证码>>: ').strip() 38 if code.upper() == self.cache: 39 print('验证码输入正确') 40 self.t.cancel() 41 break 42 43 44 obj=Code() 45 obj.check()