原文出自:Asyncio Semaphores and Bounded Semaphores Tutorial

在本教程中,我们将查看信号量和有界信号量以及它们如何在Asyncio框架内工作。

什么是信号量?

信号量最初是铁路系统架构的关键部分,著名的 Dijkstra 将这个现实世界的概念转化为我们的计算世界。

这些信号量有一个内部计数器,无论何时进行获取或释放调用,它都会递增和递减。

假设我们使用信号量保护了一个代码块,并将信号量的初始值设置为2.如果一个worker获取了信号量,我们的信号量的值将减少为1,如果第二个worker出现信号量的值将减少到0。

此时,如果另一worker出现并再次尝试,则会被拒绝。这些信号量的价值在于它们允许我们保护资源不被过度使用。

实现:

现在我们已经基本了解了什么是信号量,现在让我们看看如何在基于Asyncio的Python程序中使用它们。

在这个例子中,我们将创建一个信号量的简单实例,然后创建3个将尝试获取所述信号量的工作函数。这个信号量的初始值将是2,因此我们将看到我们的两个工作函数成功获取信号量然后释放它并允许我们的第三个工作者然后获取它。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import asyncio


async def my_worker(semaphore):
    await semaphore.acquire()
    print("成功获得了信号量")
    await asyncio.sleep(3)
    print("释放信号量")
    semaphore.release()


async def main():
    my_semaphore = asyncio.Semaphore(value=2)
    await asyncio.wait([my_worker(my_semaphore), my_worker(my_semaphore), my_worker(my_semaphore)])
    print("Main 协程")

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
print("所有 Workers 完成")
loop.close()

输出

当我们运行这个时,我们应该看到我们的前两个 Workers 能够获得信号量然后释放它,然后允许我们的第三个Workers继续自己获取信号量。

Note: 另一种写法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import asyncio

my_semaphore = asyncio.Semaphore(value=2)


async def my_worker():
    with (await my_semaphore):
        print("成功获得了信号量")
        await asyncio.sleep(3)

    print("释放信号量")


async def main():
    await asyncio.wait([my_worker(), my_worker(), my_worker()])
    print("Main 协程")

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
print("所有 Workers 完成")
loop.close()

有界信号量

普通信号量和有界信号量之间存在非常微妙的差异。有界信号量仅在不允许进行更多发布方面有所不同。如果它超过该值,则引发ValueError。