Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:如何避免这个简单功能的死锁?_Python_Python Asyncio - Fatal编程技术网

Python:如何避免这个简单功能的死锁?

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

我实现了一个名为Saver的简单类,它有两个调用方可以执行的函数。 它们是保存所有()和保存一个()

顾名思义,当我执行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,因此在编写异步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)