在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. 20175213吕正宏 MyCP(课下任务,必做)

    一.任务详情: 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bin 用来把文本文件( ...

  2. 微信小程序---获取上传图片大小

    wx.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album', 'camera'], success: funct ...

  3. 知识点---animate()动画滞后执行的解决方案

    jQuery动画: animate 容易出现连续触发.滞后反复执行的现象: 针对 jQuery 中 slideUp.slideDown.animate 等动画运用时出现的滞后反复执行等问题的解决方法有 ...

  4. css入门第一天

    一丶Web标准Web标准不是某一个标准,而是一系列标准的集合,内容与结构与表现形式的分离网页主要有四个部分组成:内容(content),结构(structure), 表现(presentation)和 ...

  5. Mysql设置大小写敏感

    1.linux下mysql安装完后是默认:区分表名的大小写,不区分列名的大小写: 2.用root帐号登录后,在/etc/my.cnf 中的[mysqld]后添加添加lower_case_table_n ...

  6. java获取request中的参数、java解析URL问号后的参数

    java获取request中的参数.java解析URL问号后的参数.有时候我们需要从request中获取参数,或者获取拼接在Url后面的参数,有时候一个一个去拿有点麻烦,一起拿出来放在一个map里面需 ...

  7. ajax 跳转页面时添加header

    在页面中添加一个form表单隐藏域,表单的一个属性是需要传的token,然后在ajax的回调函数中提交这个表单.要把这个token添加到header中就需要重写一个过滤器filter继承org.spr ...

  8. 20175314 《Java程序设计》第九周学习总结

    20175314 <Java程序设计>第九周学习总结 教材学习内容总结 根据课本的介绍下载了MySQL和Navicat for MySQL并成功对后者进行破解 MySQL客户端管理工具(如 ...

  9. 【Android端】【日志收集上报SDK相关内容测试的方案梳理总结】

    测试方案: 主要从几个方面关注,功能 性能 服务端策略(目前所有的这些上报收集等都会通过开关的精细化,通过接口方式将信息返回给APP端,APP端根据相关内容进行上报,因此基于此的上报机制及收集机制都需 ...

  10. 1. NES简介

    NES(Nintendo Entertainment System)简介 NES是北美地区对任天堂发行的第三代家用游戏机的简称. 1.CPU NES使用一颗理光[1]制造的8位2A03 NMOS处理器 ...