Linux信号量是一种进程间同步机制,用于协调多个进程对共享资源的访问,通过P(wait,资源申请)和V(signal,资源释放)操作控制并发数量,避免竞争条件,在Python中,可通过高级接口multiprocessing.Semaphore
和低级接口os
模块的信号量系统调用来实现信号量的功能。
Python中使用Linux信号量的两种方式
高级接口:multiprocessing.Semaphore
multiprocessing.Semaphore
是Python标准库提供的基于进程池的信号量实现,适用于多进程编程场景,支持计数信号量(可指定初始值),其核心是通过acquire()
方法获取资源(计数减1,若计数≤0则阻塞),通过release()
方法释放资源(计数加1)。
示例:限制同时运行的进程数
from multiprocessing import Process, Semaphore import time def worker(sem, num): sem.acquire() # P操作:获取资源 print(f"进程 {num} 正在运行") time.sleep(2) # 模拟耗时操作 print(f"进程 {num} 结束") sem.release() # V操作:释放资源 if __name__ == "__main__": sem = Semaphore(3) # 初始值为3,最多3个进程同时运行 processes = [] for i in range(5): # 创建5个进程 p = Process(target=worker, args=(sem, i)) processes.append(p) p.start() for p in processes: p.join() # 等待所有进程结束
运行结果中,任意时刻最多只有3个进程同时打印运行信息,其余进程需等待release()
后才能执行。
低级接口:os
模块的信号量系统调用
os
模块提供了直接操作Linux System V IPC信号量的接口,包括semget
(创建/获取信号量集)、semop
(执行P/V操作)、semctl
(控制信号量集),适用于需要底层精细控制的场景。
核心函数说明:
semget(key, nsems, flags)
:创建或获取信号量集,key
为唯一标识,nsems
为信号量数量,flags
包含IPC_CREAT
(创建新信号量集)等。semop(semid, sops)
:执行P/V操作,sops
为操作数组,sem_op=-1
为P操作(阻塞至资源可用),sem_op=1
为V操作(释放资源)。semctl(semid, semnum, cmd, ...)
:控制信号量集,如SETVAL
(设置初始值)、IPC_RMID
(删除信号量集)。
示例:用二值信号量保护文件写入
import os import sys from time import sleep def process1(semid): semop(semid, [{'sem_num': 0, 'sem_op': -1, 'sem_flg': 0}]) # P操作 with open("test.txt", "a") as f: f.write("进程1写入n") semop(semid, [{'sem_num': 0, 'sem_op': 1, 'sem_flg': 0}]) # V操作 def process2(semid): semop(semid, [{'sem_num': 0, 'sem_op': -1, 'sem_flg': 0}]) with open("test.txt", "a") as f: f.write("进程2写入n") semop(semid, [{'sem_num': 0, 'sem_op': 1, 'sem_flg': 0}]) if __name__ == "__main__": key = 0x1234 # 信号量集唯一标识 semid = os.semget(key, 1, 0666 | os.IPC_CREAT) # 创建信号量集,1个信号量 os.semctl(semid, 0, os.SETVAL, 1) # 初始值为1(二值信号量) pid1 = os.fork() if pid1 == 0: process1(semid) sys.exit() pid2 = os.fork() if pid2 == 0: process2(semid) sys.exit() os.waitpid(pid1, 0) # 等待子进程结束 os.waitpid(pid2, 0) os.semctl(semid, 0, os.IPC_RMID) # 删除信号量集
运行后,test.txt
中进程1和进程2的写入内容会顺序出现,避免同时写入导致数据混乱。
两种方式对比
实现方式 | 核心模块 | 适用场景 | 操作方法 | 优点 | 缺点 |
---|---|---|---|---|---|
高级接口 | multiprocessing | 多进程同步,简单场景 | acquire/release | 简单易用,自动管理 | 依赖进程池,灵活性较低 |
低级接口 | os | 底层同步,复杂控制 | semget/semop/semctl | 灵活,直接控制IPC | 复杂,需手动管理资源 |
相关问答FAQs
Q1: Python中multiprocessing.Semaphore
和os
模块的信号量有什么区别?
A1: multiprocessing.Semaphore
是高级接口,基于进程池设计,适用于多进程编程,提供acquire
/release
方法,自动管理信号量生命周期,适合简单同步场景;os
模块信号量是低级接口,直接操作System V IPC,需手动创建、操作和删除信号量集,灵活性高但复杂,适用于需要精细控制的底层同步。
Q2: 信号量与互斥锁(Lock)的区别是什么?
A2: 信号量(Semaphore)是计数同步机制,允许多个进程同时访问资源(计数>1时),适用于资源池控制(如限制数据库连接数);互斥锁(Lock)是二值信号量(计数仅0或1),只允许一个进程访问资源,适用于互斥访问(如保护共享变量),信号量更灵活,可控制并发数;互斥锁更简单,专注于互斥场景。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/15642.html