Python:如何避免这个简单功能的死锁?
我实现了一个名为Saver的简单类,它有两个调用方可以执行的函数。 它们是保存所有()和保存一个() 顾名思义,当我执行save_all()时,我希望它在循环中执行函数save_one()。 我只想确保在给定的时间内,只有一个调用方可以从外部执行save_all()或save_one()Python:如何避免这个简单功能的死锁?,python,python-asyncio,Python,Python Asyncio,我实现了一个名为Saver的简单类,它有两个调用方可以执行的函数。 它们是保存所有()和保存一个() 顾名思义,当我执行save_all()时,我希望它在循环中执行函数save_one()。 我只想确保在给定的时间内,只有一个调用方可以从外部执行save_all()或save_one() import asyncio class Saver: def __init__(self): # it's lock self.lock = asyncio.Lock() de
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,因此在编写异步Python时,应该使用async def
和wait
代替def
和yield from
由于asyncio没有可重入锁,因此解决此问题的最简单方法是只锁定API入口点。底层的实现方法可以完全避免锁定,它在系统边界得到处理。这样就不会出现死锁,因为内部\u save\u all
将调用内部\u save\u one
,并且锁只会被获取一次(在save\u call
中,在调用\u save\u all
之前,或者在save\u one
中,在调用\u save\u one
之前,视情况而定):
或者使用一个单独的标志来协调
save\u one
不应尝试获取另一个锁,或者对save\u one
和save\u all
使用单独的锁。save\u all
确实需要锁吗?另外,如果您没有在asyncio协程中使用锁,则可能需要使用线程化.Lock
。@dirn线程化.Lock
不是正确的工具,因为它会在等待获取锁时阻塞事件循环(可能导致死锁)。OP似乎在异步IO代码中使用了锁,显然是使用了来自语法的屈服。@user4815162342但OP似乎没有使用coroutine
装饰器。@dirn这是一个很好的观点,但另一方面,OP在参数列表中省略了self
,而是在函数体中使用它,像调用顶级函数一样调用方法,依此类推。所显示的代码可能只是OP实际代码的近似值,我希望它包含decorator,因为它是从过时的教程复制粘贴的。
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)