103、Python并发编程:使用信号量Semaphore实现资源有限的并发场景

Python信号量Semaphore 来控制并发任务的生成和消费,确保在任意时刻不会超出最大任务处理能力。Semaphore 在多线程编程中是一个强大的工具,可以用于管理和优化资源并发访问。它主要用于限制同时访问某个资源资源池的线程或进程的数量,类似于操作系统中的信号量概念。我们希望限制同时进行生成和消费的任务数量,以避免资源竞争或者过度消耗。来实现批量生成与消费的例子可以帮助理解如何在多线程环境中控制资源的访问。在这个例子中,我们将使用。是一种重要的同步工具,特别适用于需要控制对有限资源并发访问的场景,如连接池、线程池等。 阅读详情

引言

在前面几篇文章的基础上,应对并发编程中现成同步的需求场景:

我们可以使用锁,作为多线程同步的几个核心基础,实现对临界资源的保护,确保满足基本的互斥访问逻辑。

使用条件变量Condition,实现有固定顺序的复杂交互场景下的同步协作。

使用队列Queue,实现简单的消息中间件,支持生产者消费者模型,实现了多个工作环节的解耦、协作。

但是,如果资源有限的场景中,如何处理并发的同步呢?比如银行柜台只有5个窗口,最多同时服务5个客户,但是可能有20个客户在排队等待。比如,高铁站,只有6个检票通道,但是有500个旅客等待进展……

这就要用到本文的主角,信号量Semaphore了。

本文的主要内容有:

1、信号量的概念

2、信号量的使用场景

3、Python中Semaphore的设计及使用实例

信号量的概念

信号量(semaphore)是一种用于控制对共享资源访问的同步机制,多线程环境中,信号量可以用于限制同时访问某种资源的线程数量。

信号量,可以简单理解为一个计数器,它用于保护对有限资源的并发访问,通常来说这种有限资源是可以复用的,而不是消耗型的。

Python中的Semaphore可以实现信号量的支持。

信号量的使用,一般遵循如下规则:

1、每个线程在访问共享资源之前,必须先“获取”信号量,一般称为P操作,使其计数器减一。

2、使用完毕后,“释放”信号量,一般称为V操作,使计数器加一。

3、当计数器为零时,获取信号量的线程将阻塞,直到其他线程释放信号量。

信号量的使用场景

信号量的使用场景,一般是资源有限的并发场景下,对这些有限的共享资源的共享、复用。

通常可以将信号量应用于如下场景中:

1、流量控制:限制高并发场景中对某些关键部分的访问流量,防止系统过载。

2、限制有限资源的访问:信号量可以用于限制同时访问特定资源(比如数据库连接、文件读写、网络带宽等)的线程数量。

3、多生产者多消费者模式:可以用信号量协调多生产者多消费者的同步访问场景。

4、互斥锁的泛化:在某些情况下,可以将信号量看作是一个允许多个现成访问而不是单个线程的互斥锁。

基于信号量,可以更加便捷实现在实际工作中比较熟知的一些设计模式或者应用组件,比如:数据库连接池、线程池等。

Python中Semaphore的设计及使用实例

Semaphore的设计实现

首先通过Semaphore的相关文档说明,来看下Python中Semaphore的设计实现:

9f9ddbbda8769881fe424504c53edf8a.jpeg

9924b79e56319e64bc49e0d346447b70.jpeg

c0f50350a34ecd8abdb7ab725c82b07e.jpeg

从Python中关于Semaphore源码可以看到该对象的设计实现:

1、通过计数器维持现有资源的数量,如果不指定资源数量,默认为1,也就退化成了一个互斥锁。

2、通过持有锁对象,确保对计数器的修改是原子操作,防止竞态条件。

3、通过持有条件变量Condition对象,来管理阻塞和唤醒等待资源的线程。

4、通过acquire()方法,实现对信号量的P操作,如果信号量的内部计数器大于0,则计数器减1;如果计数器为0,则阻塞,直至计数器大于0。

5、通过release()方法,实现对信号量的V操作,将信号量内部计数器加1,并唤醒一个阻塞在P操作上的线程(如果有的话)。

6、Semaphore对象实现了上下文管理的__enter__()和__exit__()魔术方法,所以可以通过with语法糖进行便捷的管理。

使用实例

我们通过Semaphore简单模拟一下银行柜员在柜台服务客户的业务场景:

1、有5个柜台,相应的有5个银行柜员提供业务服务。

2、共有50个客户需要在柜台办理各种业务。

直接看代码:

from threading import Thread, Semaphore
import time


class Bank:
    def __init__(self, max_counter):
        self.counter = Semaphore(max_counter)

    def service(self, customer):
        print(f'客户{customer}需要办理业务')
        with self.counter:
            print(f'====有柜台空闲,开始接待{customer},办理相关业务===')
            # 模拟服务
            time.sleep(1)
            print('业务办理完成')


def customer_business(bank, customer):
    bank.service(customer)


if __name__ == '__main__':
    bank = Bank(5)
    customers = [Thread(target=customer_business, args=(bank, f'客户{i}')) for i in range(50)]
    for customer in customers:
        customer.start()

    for customer in customers:
        customer.join()

执行结果:

刚开始启动,由于只有5个柜台,所以0-4号顾客直接进行业务办理了,之后的客户要等待了。

f4c343fbdfd47fcfd04405fe956d54fb.jpeg

后续有业务办理完成,柜台空闲,则继续服务后面的客户:

d3b5353cad48f980c982ef0e86f97384.jpeg

总结

本文首先回顾了之前介绍到的锁、条件变量和队列各自所能应对的并发同步场景,引出了资源有限的同步场景中的主角Semaphore,分别介绍了Semaphore的设计实现及使用案例。

感谢您的拨冗阅读。

a7bf8d4fd630aab6d636bcf031f0c774.jpeg

Python信号量semaphore semaphone信号量 和Lock很像,信号量对象内部维护一个倒数计数器,每一次acquire都会减1,当acquire方法发现计数为0就阻塞请求的线程,直到其他的线程对信号量release后,计数大于0,恢复阻塞的线程 名称 含义 Semaphore(value=1) 构造方法。value小于0,抛ValueError异常 acquire(blocking=True,timeout=None) 获取信号量,计数器减1,获取成功返回True releas... 阅读详情

相关推荐

Python中的Semaphore是什么?

如果计数器大于零,表示有可用的资源Semaphore会将计数器减一,允许线程访问资源。如果计数器为零,表示没有可用的资源Semaphore会阻塞线程,直到有资源可用为止。当线程使用资源后,它会释放资源,并将计数器加一,以允许其他线程访问。通过合理地设置计数器的值,我们可以控制同一时间内能够访问资源的线程数量,从而实现线程间的协作和同步。运行上述代码,你会发现只有两个线程能够同时访问资源,而第三个线程会在前两个线程中的任意一个释放资源后才能获得访问权限。最后,我们创建了三个线程,并启动它们。

HackNebulaZ的博客 416

python 信号量 semaphore

信号量 信号量(英语:semaphore)又称为信号标, 是一个同步对象,用于保持在0至指定最大值之间的一个计数值。 当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一; 当线程完成一次对semaphore对象的释放(release)时,计数值加一。 当计数值为0,则线程等待该semaphore对象不再能成功直至该semaphore对象变成signaled状态。 semaphore对象的计数值大于0,为signaled状态;计数值等于0,为nonsignaled状态. 信号量的概念

LuiChun 5380

【信息科学与工程学】计算机科学与自动化——第三百零五篇 计算机系统中的各类运算操作01

编号类型领域运算操作运算类型算法算法的详细设计及数学分析参数列表及参数的数值设计应用场景 (100+条)集合运算​1集合运算关系代数并集 (Union)集合运算归并排序去重合并两个集合,去除重复元素。时间复杂度 O(n+m),n,m为两集合大小。输入:集合A, B。输出:A∪B。数据集成、多表结果合并、去重后的全量数据提取。2集合运算关系代数交集 (Intersection)集合运算哈希交集找出同时属于两个集合的元素。平均时间复杂度 O(min(n,m)),最坏 O(n*m)。输入:集合A, B。输出:A∩

weixin_49199313的博客 1301

python信号量Semaphore

Python中,信号量Semaphore)主要用来控制多个线程或进程对共享资源的访问。信号量本质上是一种计数器,它维护一个许可(permit)数量,每次 acquire() 函数被调用时,如果还有剩余的许可,则减少一个,并允许执行;如果没有剩余许可,则阻塞当前线程直到其他线程释放信号量。在这个例子中,我们创建了一个最多允许3个线程同时执行的信号量。当超过3个线程尝试进入临界区时,其余线程将等待信号量被释放。每个成功获取信号量的线程在完成其工作后会释放信号量,以便其他等待的线程能够继续执行。

semicolon_hello的专栏 1557

Python异步编程实战:aiohttp实现800并发HTTP请求优化

异步编程是现代高性能服务的核心技术,通过事件循环和非阻塞IO实现并发处理。Python的asyncio库结合aiohttp框架,可以构建高效的HTTP客户端/服务端。在连接池管理、并发控制、内存优化等关键环节进行调优后,单机可实现800+并发请求处理能力。这种方案特别适用于爬虫开发、API聚合、实时数据处理等场景,相比传统同步方式有10倍以上的性能提升。通过TCP连接器配置、uvloop事件循环优化等技术手段,开发者可以在不依赖分布式架构的情况下,显著提升Python服务的吞吐量。

weixin_33857230的博客 394

VC++多线程控制动态图标:Win32 API实现与线程同步详解

多线程编程是提升桌面应用响应性和用户体验的核心技术,其原理在于将耗时任务与用户界面操作分离到不同执行流,避免主线程阻塞导致的界面卡顿。在Windows平台,通过Win32 API的CreateThread函数创建工作线程,结合事件、临界区等同步机制,可以实现高效的后台任务处理。这一技术对于需要实时反馈的应用场景价值显著,例如文件传输、数据计算或网络请求过程中的状态指示。本文聚焦于利用VC++和Win32线程模型,实现一个由工作线程驱动的动态图标控件,详细解析了从线程创建、自定义消息通信到双缓冲绘图消除闪烁的

411

Pixelle-Video深度重构:从使用者到架构师的工作流自定义技术栈改造

在AI视频生成领域,Pixelle-Video代表了当前技术栈的最高集成水平,但其真正的技术价值远不止于开箱即用的视频生成能力。本文将从架构师视角深入剖析Pixelle-Video的工作流重构机制,探索如何通过深度自定义实现企业级AI视频生产流水线的技术架构优化。 ## 架构层:模块化设计与可扩展性分析 Pixelle-Video的架构设计体现了现代AI应用的核心思想——将复杂的视频生成流程拆

gitblog_00882的博客 472

Qt开发入门:从零到跨平台GUI低手

Qt开发入门:从零到跨平台GUI低手

Yusei_0523的博客 396

Python同步编程框架Semaphore使用,限制线程的并发数量

Python同步编程框架Semaphore是一种同步原语,允许多个线程或进程共享有限数量的资源

captain 1125

信号量的秘密:Python中的Semaphore详解

随着计算机硬件的发展,多核处理器已经成为了标准配置。这使得开发人员可以利用并发编程技术来提高应用程序的性能。然而,在并发环境下,资源共享和访问控制成了一个棘手的问题。Semaphore信号量)就是一种常用的解决此类问题的技术。通过限制对共享资源的同时访问数量,Semaphore可以有效地防止资源的竞争条件,保证程序的正确性。

qq_44771627的博客 1694

Python 多线程编程-05-threading 模块 - Semaphore 和 BoundedSemaphore

threading.Semaphore 可以理解为一个内置的计数器,当调用 acquire 方法时候内置计数器 -1,对应着申请资源;调用 release 方法时候内置计数器+1,对应着释放可用资源。 BoundedSemaphoreSemaphore 的区别的区别在于threading.BoundedSemaphore 会在过多的使用 release() 时候报错 " ValueError: Semaphore released too many times "。

一分耕耘一分收获 2926

python---多进程并发控制 Semaphore 与 互斥锁 LOCK

一、了解锁 应用场景举例描述: Lock 互斥锁:举例说明–有三个同事同时需要上厕所,但是只有一间厕所,将同事比作进程,多个进程并打抢占一个厕所,我们要保证顺序优先, 一个个来,那么就必须串行,先到先得,有人使用了,就锁住,结束后剩余的人继续争抢 1、利用Lock来处理 模拟三个同事抢占厕所 from multiprocessing import Process from multiprocessing import Lock import time import random def task1(p,

CN_LiTianpeng的博客 2289

Python的多线程

需要导入threading库中Thread类,例如 from threading import Thread。

qq_41304832的博客 441

[Python学习日记-95] 并发编程之多线程 —— 死锁、递归锁与信号量Semaphore

前面我们介绍了多线程中的互斥锁,它解决了多线程时会造成的数据安全问题,但是加锁也带来了其他问题,其中死锁最为著名;递归锁用于解决特定场景下的锁冲突;信号量则能灵活控制资源并发访问量。下面让我们来一起探究一下 死锁、递归锁与信号量究竟是怎么一回事吧。

JovaZou的成长之路 889

python并发-semaphore

semaphore信号量可以通过内置计数器来控制同时运行线程的数量 每当调用acquire()时,内置计数器-1,直到为0的时候阻塞 每当调用release()时,内置计数器+1,并让某个线程的acquire()从阻塞变为不阻塞 Semaphore: 在调用release()函数时,不会检查,增加的计数是否超过上限(没有上限,会一直上升) BoundedSemaphore: 在调用release()函数时,会检查,增加的计数是否超过上限,这样就保证了使用的计数 Thread :线程类,这是用的最多的一个

qq_41969287的博客 670

一文速通Python并行计算:03 Python多线程编程-多线程同步(上)—基于互斥锁、递归锁和信号量

Python 多线程编程中,线程同步是确保多个线程安全访问共享资源的关键技术。本篇文章介绍了互斥锁(Lock)、递归锁(RLock) 和 信号量Semaphore) 的概念与应用。互斥锁用于防止多个线程同时修改数据,递归锁适用于嵌套锁定场景,而信号量则限制同时访问资源的线程数。

weixin_44719294的博客 1168

PythonSemaphore 信号量对象、Event事件、Condition

Semaphore 信号量对象 信号量是一个更高级的锁机制。信号量内部有一个计数器而不像锁对象内部有锁标识,而且只有当占用信号量的线程数超过信号量时线程才阻塞。这允许了多个线程可以同时访问相同的代码区。 Semaphore管理一个内置的计数器,每当调用acquire()时内置计数器-1;调用release() 时内置计数器+1; 计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其...

gmHappy 1831

Python——信号量、条件变量、事件

1.信号量Semaphore信号量通常用于保护数量有限资源,例如数据库服务器。在资源数量固定的任何情况下,都应该使用有界信号量。在生成任何工作线程前,应该在主线程中初始化信号量信号量提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器大于0,则将其减1,如果内部计数器等于0,则会阻塞该线程,知道有线程调用release方法将内部计数器更新到大于1位置。 信号量也是一把锁,用来控制线程并发数。信号量通过一...

W_000的博客 1922
上一篇: 102、Python并发编程:Queue与生产者消费者模型实现解耦、协作
下一篇: 104、Python并发编程:基于事件Event实现多线程间的同步
南宫理的日知录
博客等级 码龄16年 2591粉丝 155原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南宫理的日知录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值