在python的多线程体系中,一共有4种锁:
- 同步锁(互斥锁):Lock;
- 递归锁:RLock;
- 信号量:Semaphore;
- 同步条件锁:Condition.
信号量(semaphore)是一种可以控制线程并发数的锁,也就是控制同一时刻有多少线程可以获取内存资源。信号量通过内部计数器来控制线程的进入和执行,实例属性value用来设置计数器的大小(默认为1)。这就好比在一个地方有10个停车位(value=10),同时可以停10辆车;当第11辆车过来时,需要等待其他车辆把停车位让出来。信号量相当于批量给线程加锁,Lock和RLock都是给一个线程加锁,而我们实例化一个信号量后,就可以给多个线程加锁,保证同一时刻多个线程在执行(其实是来回切换)。
Semaphore内部也定义了acquire()和release()两个方法。当调用acquire()方法时内部计数器减1,有线程获取了执行权;调用release()方法时计数器加1,有线程释放了执行权,其他线程就可以进入执行。当计数器的值等于0时,acquire()方法会阻塞线程的执行,直到有线程调用release()方法后使该计数器的值大于0。
- acquire(blocking=True, timeout=None):当使用默认参数调用该方法时,如果内部计数器大于1,将其减1。
- 第一个参数blocking,默认为True,即当计数器(value值)为0时阻塞线程进入执行,直到有其他线程调用release()方法将计数器设置到大于0,这个过程有严格的联锁控制,以保证如果有多条线程正在等待解锁,release() 调用只会唤醒其中一条线程(随机唤醒)。此时这个方法返回True,或无限阻塞;如果blocking=False,则不阻塞线程的执行,但是这种情况下其他线程获取执行失败,此时acquire方法返回False。
- 第二参数timeout,设置最多阻塞多少秒,如果超时(即在这段时间内线程并未获取执行权),就会返回False。
- release():没有参数,调用该方法时,使内部计数器加1(释放某个线程,允许其他等待线程进入执行)。
示例1:当调用默认参数的acquire方法时:
1 import threading, time 2 3 4 class MyThread(threading.Thread): 5 6 def run(self): 7 get_flag = semaphore.acquire() # 线程获取执行权 8 print("get_flag(before if)--->", get_flag) # 打印acquire()方法的返回值 9 if get_flag: 10 print(self.name, "...at ", time.ctime()) 11 time.sleep(3) # 每个线程执行3秒 12 print("%s has done... at %s" % (self.name, time.ctime())) 13 semaphore.release() 14 15 16 if __name__ == "__main__": 17 18 semaphore = threading.Semaphore(2) # 容量为2,每次允许2个线程执行 19 20 threads = [] 21 22 for i in range(10): # 创建10个线程实例 23 threads.append(MyThread()) 24 25 for t in threads: 26 t.start()
打印结果如下:
get_flag(before if)---> True Thread-1 ...at Mon Mar 25 10:51:21 2019 get_flag(before if)---> True Thread-2 ...at Mon Mar 25 10:51:21 2019 Thread-2 has done... at Mon Mar 25 10:51:24 2019 get_flag(before if)---> True Thread-1 has done... at Mon Mar 25 10:51:24 2019 Thread-3 ...at Mon Mar 25 10:51:24 2019 get_flag(before if)---> True Thread-4 ...at Mon Mar 25 10:51:24 2019 Thread-4 has done... at Mon Mar 25 10:51:27 2019 Thread-3 has done... at Mon Mar 25 10:51:27 2019 get_flag(before if)---> True get_flag(before if)---> True Thread-6 ...at Mon Mar 25 10:51:27 2019 Thread-5 ...at Mon Mar 25 10:51:27 2019 Thread-5 has done... at Mon Mar 25 10:51:30 2019 Thread-6 has done... at Mon Mar 25 10:51:30 2019 get_flag(before if)---> True get_flag(before if)---> True Thread-7 ...at Mon Mar 25 10:51:30 2019 Thread-8 ...at Mon Mar 25 10:51:30 2019 Thread-7 has done... at Mon Mar 25 10:51:33 2019 Thread-8 has done... at Mon Mar 25 10:51:33 2019 get_flag(before if)---> True get_flag(before if)---> True Thread-9 ...at Mon Mar 25 10:51:33 2019 Thread-10 ...at Mon Mar 25 10:51:33 2019 Thread-10 has done... at Mon Mar 25 10:51:36 2019 Thread-9 has done... at Mon Mar 25 10:51:36 2019 Process finished with exit code 0
可以看到,当使用默认blocking=True时,每个线程都成功地获取了执行权。每次允许2个线程执行,其他线程会被阻塞,等待被执行的线程释放执行权后,其他线程再进入执行。
示例2:当blocking=False时
1 import threading, time 2 3 4 class MyThread(threading.Thread): 5 6 def run(self): 7 get_flag = semaphore.acquire(blocking=False) 8 print("get_flag(before if)--->", get_flag) 9 if get_flag: 10 print(self.name, "...at ", time.ctime()) 11 time.sleep(3) 12 print("%s has done... at %s" % (self.name, time.ctime())) 13 semaphore.release() 14 15 16 if __name__ == "__main__": 17 18 semaphore = threading.Semaphore(2) 19 20 threads = [] 21 22 for i in range(10): 23 threads.append(MyThread()) 24 25 for t in threads: 26 t.start()
打印结果:
get_flag(before if)---> True Thread-1 ...at Mon Mar 25 10:57:27 2019 get_flag(before if)---> True Thread-2 ...at Mon Mar 25 10:57:27 2019 get_flag(before if)---> False get_flag(before if)---> False get_flag(before if)---> False get_flag(before if)---> False get_flag(before if)---> False get_flag(before if)---> False get_flag(before if)---> False get_flag(before if)---> False Thread-2 has done... at Mon Mar 25 10:57:30 2019 Thread-1 has done... at Mon Mar 25 10:57:30 2019 Process finished with exit code 0
可以看到,第一批的线程获取了执行权;但是其他线程并没有被阻塞(blocking=False),所以它们也会去争取执行权,但是获取失败,acquire()方法返回了False。即便线程释放了执行权,其他线程也不再去争取了。所有线程就会在第一批线程执行结束后退出。
参考:
http://www.cnblogs.com/yuanchenqi/articles/6248025.html
https://blog.csdn.net/asdasdasd123123123/article/details/84139000