在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)的更多相关文章

  1. C# 多线程之一:信号量Semaphore

    通过使用一个计数器对共享资源进行访问控制,Semaphore构造器需要提供初始化的计数器(信号量)大小以及最大的计数器大小 访问共享资源时,程序首先申请一个向Semaphore申请一个许可证,Sema ...

  2. 经典线程同步 信号量Semaphore

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...

  3. 互斥锁Mutex与信号量Semaphore的区别

    转自互斥锁Mutex与信号量Semaphore的区别 多线程编程中,常常会遇到这两个概念:Mutex和Semaphore,两者之间区别如下: 有人做过如下类比: Mutex是一把钥匙,一个人拿了就可进 ...

  4. 信号量 Semaphore

    一.简介         信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用,负责协调各个线程, 以保证它们能够正确.合理的使用公共资源. Semaphore可以控制某个资源可被同时 ...

  5. windows核心编程-信号量(semaphore)

    线程同步的方式主要有:临界区.互斥区.事件.信号量四种方式. 前边讲过了互斥器线程同步-----windows核心编程-互斥器(Mutexes),这章我来介绍一下信号量(semaphore)线程同步. ...

  6. 秒杀多线程第八篇 经典线程同步 信号量Semaphore

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <且不超过最大资源数量. 第三个參数能够用来传出先前的资源计数,设为NULL表示不须要传出. 注意:当 ...

  7. 转:【Java并发编程】之二十三:并发新特性—信号量Semaphore(含代码)

    载请注明出处:http://blog.csdn.net/ns_code/article/details/17524153 在操作系统中,信号量是个很重要的概念,它在控制进程间的协作方面有着非常重要的作 ...

  8. 多线程面试题系列(8):经典线程同步 信号量Semaphore

    前面介绍了关键段CS.事件Event.互斥量Mutex在经典线程同步问题中的使用.本篇介绍用信号量Semaphore来解决这个问题. 首先也来看看如何使用信号量,信号量Semaphore常用有三个函数 ...

  9. java笔记--对信号量Semaphore的理解与运用

    java Semaphore 信号量的使用: 在java中,提供了信号量Semaphore的支持. Semaphore类是一个计数信号量,必须由获取它的线程释放, 通常用于限制可以访问某些资源(物理或 ...

  10. 对信号量Semaphore的理解与运用

    转: java笔记--对信号量Semaphore的理解与运用 java Semaphore 信号量的使用: 在java中,提供了信号量Semaphore的支持. Semaphore类是一个计数信号量, ...

随机推荐

  1. vscode垂直选中列选中

    VSCode列选择快捷键:Alt+Shift+左键

  2. springmvc+mybatis环境搭建

    1.spring+mybatis 环境搭建: A.配置jdbc和dbcp数据源:注意版本com.mysql.cj.jdbc.Driver B.配置sessionfactory,绑定dbcp及配置map ...

  3. linux下open-vswitch安装卸载操作

    一. ovs 从源码编译安装: 安装依赖项: ? 1 2 3 4 5 6 7 8 9 10 11 # apt install make # apt install gcc # apt install ...

  4. CSS 背景图像 重复图像

    重复图像 background-repeat 属性可以重复图像,这对于小图片来说是福音. background-repeat 属性有6个值: repeat 背景图像在垂直方向和水平方向都重复 repe ...

  5. 云笔记项目-Spring事务学习-传播MANDATORY

    接下来测试事务传播属性MANDATORY Service层 所有Service层实现类都设置事务传播属性为MANDATORY. LayerT层代码 package LayerT; import jav ...

  6. Linux下使用ps命令查看某个进程文件的启动位置

    ps -ef|grep shutdown ls -al /proc/4170

  7. VS2017企业版密钥

    Visual Studio 2017(VS2017) 企业版 Enterprise 注册码:NJVYC-BMHX2-G77MM-4XJMR-6Q8QFVisual Studio 2017(VS2017 ...

  8. Linux - Ubuntu 图形界面入门

    Ubuntu 图形界面入门 目标 熟悉 Ubuntu 图形界面的基本使用 01. Ubuntu 的任务栏 02. 窗口操作按钮 03. 窗口菜单条 ——本文源自<黑马程序员>

  9. git log命令常用参数集合

    git log 查看 提交历史 默认不用任何参数的话,git log 会按提交时间列出所有的更新,最近的更新排在最上面. 常用的格式占位符写法及其代表的意义.选项 说明%H 提交对象(commit)的 ...

  10. Taro 列表循环--点赞功能图片切换

    图片,未点击与点击 页面编写如下, 绑定我们的事件,继续: 附带注:Taro中不能使用 catchEvent 的方式阻止事件冒泡.你必须明确的使用 stopPropagation. 列表中点赞图片的切 ...