信号量(Semaphore)
在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方法时:
import threading, time
class MyThread(threading.Thread):
def run(self):
get_flag = semaphore.acquire() # 线程获取执行权
print("get_flag(before if)--->", get_flag) # 打印acquire()方法的返回值
if get_flag:
print(self.name, "...at ", time.ctime())
time.sleep(3) # 每个线程执行3秒
print("%s has done... at %s" % (self.name, time.ctime()))
semaphore.release()
if __name__ == "__main__":
semaphore = threading.Semaphore(2) # 容量为2,每次允许2个线程执行
threads = []
for i in range(10): # 创建10个线程实例
threads.append(MyThread())
for t in threads:
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时
import threading, time
class MyThread(threading.Thread):
def run(self):
get_flag = semaphore.acquire(blocking=False)
print("get_flag(before if)--->", get_flag)
if get_flag:
print(self.name, "...at ", time.ctime())
time.sleep(3)
print("%s has done... at %s" % (self.name, time.ctime()))
semaphore.release()
if __name__ == "__main__":
semaphore = threading.Semaphore(2)
threads = []
for i in range(10):
threads.append(MyThread())
for t in threads:
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
信号量(Semaphore)的更多相关文章
- C# 多线程之一:信号量Semaphore
通过使用一个计数器对共享资源进行访问控制,Semaphore构造器需要提供初始化的计数器(信号量)大小以及最大的计数器大小 访问共享资源时,程序首先申请一个向Semaphore申请一个许可证,Sema ...
- 经典线程同步 信号量Semaphore
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...
- 互斥锁Mutex与信号量Semaphore的区别
转自互斥锁Mutex与信号量Semaphore的区别 多线程编程中,常常会遇到这两个概念:Mutex和Semaphore,两者之间区别如下: 有人做过如下类比: Mutex是一把钥匙,一个人拿了就可进 ...
- 信号量 Semaphore
一.简介 信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用,负责协调各个线程, 以保证它们能够正确.合理的使用公共资源. Semaphore可以控制某个资源可被同时 ...
- windows核心编程-信号量(semaphore)
线程同步的方式主要有:临界区.互斥区.事件.信号量四种方式. 前边讲过了互斥器线程同步-----windows核心编程-互斥器(Mutexes),这章我来介绍一下信号量(semaphore)线程同步. ...
- 秒杀多线程第八篇 经典线程同步 信号量Semaphore
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <且不超过最大资源数量. 第三个參数能够用来传出先前的资源计数,设为NULL表示不须要传出. 注意:当 ...
- 转:【Java并发编程】之二十三:并发新特性—信号量Semaphore(含代码)
载请注明出处:http://blog.csdn.net/ns_code/article/details/17524153 在操作系统中,信号量是个很重要的概念,它在控制进程间的协作方面有着非常重要的作 ...
- 多线程面试题系列(8):经典线程同步 信号量Semaphore
前面介绍了关键段CS.事件Event.互斥量Mutex在经典线程同步问题中的使用.本篇介绍用信号量Semaphore来解决这个问题. 首先也来看看如何使用信号量,信号量Semaphore常用有三个函数 ...
- java笔记--对信号量Semaphore的理解与运用
java Semaphore 信号量的使用: 在java中,提供了信号量Semaphore的支持. Semaphore类是一个计数信号量,必须由获取它的线程释放, 通常用于限制可以访问某些资源(物理或 ...
- 对信号量Semaphore的理解与运用
转: java笔记--对信号量Semaphore的理解与运用 java Semaphore 信号量的使用: 在java中,提供了信号量Semaphore的支持. Semaphore类是一个计数信号量, ...
随机推荐
- C# 异步示例代码
在 使用BackgroundWorker组件 一文中,阐述了在Winform编程中,使用BackgroundWorker组件实现异步调用,本文主要讲述利用委托实现异步. 以下描述摘抄于MSDN: 异步 ...
- Taro之使用百度地图
适配h5的时候要使用地图功能获取位置,选取了百度地图.首先在index.html文件引入. <script type="text/javascript" src=" ...
- Java复习题
1.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 答:可以,但只能有一个public,并且public类名与文件名一致 2.Java有没有goto? ...
- requests+django+bs4实现一个web微信的功能
前言: 今天我们利用requests模块+django+bs4浏览器来实现一个web微信的基本功能,主要实现的功能如下 a.实现返回二维码 b.实现手机扫码后二维码变成变成头像 c.实现手机点击登陆成 ...
- [leetcode]61. Rotate List旋转链表
Given a linked list, rotate the list to the right by k places, where k is non-negative. Example 1: I ...
- 摘选改善Python程序的91个建议
1.理解Pythonic概念 Pythonic Tim Peters 的 <The Zen of Python>相信学过 Python 的都耳熟能详,在交互式环境中输入import thi ...
- GlusterFS
1. GlusterFS概述 GlusterFS是Scale-Out存储解决方案Gluster的核心,它是一个开源的分布式文件系统,具有强大的横向扩展能力,通过扩展能够支持数PB存储容量和处 ...
- 十、JAVA面试简答
2.ASCII编码表的常识 3.&和&&,|和||的区别 下面我们就分成三组对问题进行分析:分别是&和&&,|和||及~和!. 1.&是按位与操 ...
- PCB设计基本流程
[PCB设计基本流程]1.准备原理图和网络表2.电路板规划3.参数设置4.导入网标5.布局6.布线7.规则检查与手工调整8.输出文件 [具体步骤]1.在原理图环境下:Tool——>Footpri ...
- 关于js中操作数组的一些方法
网上找的通篇看了一遍讲的很透收藏了! 转自(https://www.cnblogs.com/blogs-8888/p/6518683.html) 1.锁定数组的长度(让数组的长度变成只读). 1 2 ...