我实现了一个名为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 def
和await
代替def
和yield 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)