Python:如何不让这个简单的功能陷入僵局?



我实现了一个名为Saver的简单类,它有两个调用者可以执行的函数。 它们是save_all()save_one()

顾名思义,当我执行 save_all() 时,我希望它在循环中执行函数 save_one()。 我只想确保只有一个调用者可以在给定时间从外部执行 save_all() 或 save_one()。


import asyncio
class Saver:
def __init__(self):
# it's lock
self.lock = asyncio.Lock()

def save_all():
yield from self.lock.acquire()
for i in range(3):
save_one(i)
self.lock.release()
def save_one():
yield from self.lock.acquire()
print(i)
self.lock.release()

现在发生的情况是,如果我调用 save_all(),它会获取锁,并且永远不会执行 save_one() print() 语句。

如何确保只有调用方可以从外部调用 save_all() 或 save_one():

saver = Saver()
saver.save_all()

save_one()中的打印不会如图所示在代码中执行,因为代码永远不会等待save_one(),它只是调用它。(但是代码还有其他微不足道的缺陷,所以也许它更像是伪代码。另请注意,不推荐使用 yield-from 协程,因此在编写异步 Python 时,应使用async defawait代替defyield from

由于 asyncio 没有附带可重入锁,因此解决此问题的最简单方法是仅锁定 API 入口点。底层实现方法可以完全避免锁定,它在系统边界处得到处理。然后没有死锁,因为内部_save_all会调用内部_save_one,并且锁只会被获取一次(在save_call,在调用_save_all之前,或在save_one,在调用_save_one之前,视情况而定):

class Saver:
def __init__(self):
self.lock = asyncio.Lock()
async def save_all(self):
async with self.lock:
await self._save_all()
async def save_one(self):
async with self.lock:
await self._save_one()
async def _save_all(self):
# private method, must be invoked with the lock held
for i in range(3):
await self._save_one(i)
async def _save_one(self, i):
# private method, must be invoked with the lock held
print(i)

最新更新