在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. [转] ESXI6.5 误将硬盘阵列卡配置为passthru直通模式后, 找不到硬盘的问题

    There is no easy way to do it, it seems. So I wanted to say that I couldn't afford to do an upgrade ...

  2. Tomcat的三种安装方式:解压版、安装版、配置成Windows服务版

    https://blog.csdn.net/Jessica_XLF/article/details/81711429

  3. c++学习路线连接

    https://blog.csdn.net/qq_36482772/article/category/7396881/4?

  4. 搞搞电脑微信表情的破解(.dat转png or jpg)

    首先感谢:https://blog.csdn.net/weixin_42440768/ 因为狗子喜欢之前那个头像,但是没找到,于是我想看看我们之前的斗图过程中有没有发她的头像. 这是做这件事情的起因. ...

  5. centos 7 开机yum

    yum -y install net-tools yum -y install wget

  6. jdk和tomcat的安装

    https://blog.csdn.net/angel_w/article/details/78580528

  7. 使用SQL语句查询表及表字段类型说明

    今天突然遇到有人要数据库表及表字段说明,数据库表太多又不能一个个表去找,就想想SQL是否能直接查询出来. 经过查询资料,加上一些自己的一些调整写了一个sql语句,在此记录一下,以方便日后查找使用. S ...

  8. git GUI设置长期记住密码

    git config --global credential.helper store

  9. Gulp入门及简单使用

    前言 什么是gulp?gulp有什么用?为什么用gulp? gulp是前端开发的一种构建工具. 构建工具可以帮助我们工程化地开发项目,比如搭建本地服务器.编译CSS预处理器.保存文件后自动刷新浏览器而 ...

  10. php socket多进程简单服务器(一)

    进程,线程  IO复用,协程都是处理完成并发的方式 socket分为  三步 服务器监听,客户端请求,连接确认, 每次连接都由当前进程来处理,可以通过IO复用来解决这个问题, 这次通过进程来完成并发请 ...