信号量(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类是一个计数信号量, ...
随机推荐
- 从 TFS 迁移源代码到 git
准备工具: https://github.com/git-tfs/git-tfs 具体的安装步骤上面的 readme.md 中有说明.通过 Chocolatey 安装,如果本地没有 git ,会自动安 ...
- 关于activity的一点总结(一)
关于activity的重点: 参考网址:https://blog.csdn.net/qq_26787115/article/details/52556842 一.activity生命周期. 二..启动 ...
- jq动画设置图片抽奖
(因为自己是前端刚入门的小白所以中间出现很多问题,不过这对于我来说就是一次经验的积累) 预想效果:点击"开始",图片循环旋转,不是同时的效果,而是有一定的时间差.点击"开 ...
- appium 移动端自动化测试一
最近公司决定使用appium为主体框架做一个移动端得自动化测试系统,我会陆续记录项目得进展. 1.首先是appium环境得搭建, 需要安装appium-server ,appium-desktop, ...
- 某公司的U3D笔试题
某公司的U3D笔试题 今天这套笔试题感觉做得一般. 随后是二对一的技术面试,但涉及的技术细节相对较少,更多的是对以前工作.项目经历的询问. 然后说今天先到这里,让我等通知. 我还特意问了一下,通知 ...
- 用python计算圆周率Π
一.要求: 1.计算到圆周率后面越多位越好. 2.用进度条显示计算的进度. 3.要求给出圆周率Π的具体计算方法和解释. 二.算法: 1.拉马努金公式: 2.高斯-勒让德公式: 设置初始值: 反复执行以 ...
- IDEA cannot resolve symbol “xxxx”
有缓存 多试两次就可以了. 技术交流群:816227112
- Git命令参考手册
git init # 初始化本地git仓库(创建新仓库) git config --global user.name "xxx" # 配置用户名 git config --glob ...
- js如何实现重载
所谓重载,就是一组相同的函数名,有不同个数的参数,在使用时调用一个函数名,传入不同参数,根据你的参数个数,来决定使用不同的函数!但是我们知道js中是没有重载的,因为后定义的函数会覆盖前面的同名函数,但 ...
- 【aardio】回车换行符
回车换行符 在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符.但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字 ...