概述
在Python的asyncio模块中,Semaphore(信号量)和BoundedSemaphore(有界信号量)都用于控制在异步编程中对共享资源的访问。它们通过限制同时可以访问共享资源的协程数量来管理并发。
-
Semaphore(信号量):
-
Semaphore是asyncio中的一个计数器,用于跟踪允许访问共享资源的任务数量。当计数器为正时,允许访问资源;当计数器为零时,资源被锁定,其他任务需要等待释放资源后才能访问。Semaphore的计数器在初始化时被设置为一个非负整数。当计数器为1时,Semaphore行为类似于Lock(锁),即只允许一个任务访问资源;当计数器大于1时,允许多个任务同时访问资源。
-
-
BoundedSemaphore(有界信号量):
-
BoundedSemaphore是asyncio中的一种特殊类型的Semaphore,它有一个上限值。与普通的Semaphore不同,BoundedSemaphore的计数器在初始化时被设置为一个非负整数,并且还有一个上限值。当计数器达到上限值时,任何尝试增加计数器的操作都会被阻塞,直到有其他任务释放了资源并将计数器降低。
在Python的asyncio库中,Semaphore和BoundedSemaphore是用于控制异步任务访问共享资源或执行关键部分的同步原语。
-
Semaphore
Semaphore是一个通用的信号量,它可以有一个非负整数值,表示可用的“许可”数量。每次一个异步任务需要访问共享资源时,它会尝试获取一个许可;如果许可可用,任务会继续执行;如果没有许可可用,任务会等待,直到有许可可用。
你可以使用Semaphore来限制并发执行的任务数量,即使资源是无限的。
示例:
from asyncio import Semaphore, create_task, run
sem = Semaphore(3) # 最多允许3个任务同时执行
async def worker():
async with sem:
# 执行某些操作
print(f"Worker is running, current semaphore value: {sem._value}")
async def main():
tasks = [create_task(worker()) for _ in range(10)]
await asyncio.gather(*tasks)
run(main())
BoundedSemaphore
BoundedSemaphore是Semaphore的一个特殊版本,它有一个固定的最大值,表示许可的总数。尝试创建一个超过其最大值的BoundedSemaphore会引发ValueError。
使用BoundedSemaphore可以确保你不会意外地创建过多的许可,这在某些场景中可能是有用的,例如,当你有一个固定数量的物理资源(如数据库连接)并且不想超出这个数量时。
示例:
from asyncio import BoundedSemaphore, create_task, run
sem = BoundedSemaphore(3) # 最多允许3个许可
async def worker():
async with sem:
# 执行某些操作
print(f"Worker is running, current semaphore value: {sem._value}")
async def main():
tasks = [create_task(worker()) for _ in range(10)]
await asyncio.gather(*tasks)
run(main())
在这两个示例中,尽管我们创建了10个任务,但由于Semaphore或BoundedSemaphore的限制,最多只有3个任务可以同时执行。其他任务会等待,直到有任务完成并释放许可。
注意:在实际代码中,通常不建议直接访问_value属性来检查信号量的值,因为这是一个内部实现细节,并可能在未来的版本中发生变化。这里只是为了解释目的而使用。