取消任务时,异步锁会死锁

2024-05-12 20:28:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近使用pythonsocketio和aiohttp编写了一个客户机/服务器应用程序,我的应用程序基于异步名称空间(服务器端),此外,我的on\u消息事件中有许多等待调用,因此我必须使用异步锁来确保维护所需的流。为了实现这个行为,我编写了一个装饰器,并用它包装了每个关键的节类型函数。你知道吗

@async_synchronized('_async_mutex')
    async def on_connect(self, sid, environ):
        self._logger.info("client with sid: {} connected to namespace: {}!".format(
            sid, __class__.__name__))
        important_member = 1
        await other_class.cool_coroutine()
        important_member = 2

在我的构造函数中,我初始化了_async_mutex = asyncio.Lock()

装饰师:

def async_synchronized(tlockname):
    """A decorator to place an instance based lock around a method """

    def _synched(func):
        @wraps(func)
        async def _synchronizer(self, *args, **kwargs):
            tlock = self.__getattribute__(tlockname)
            try:
                async with tlock:
                    return await func(self, *args, **kwargs)
            finally:
                pass
        return _synchronizer

    return _synched

现在,在任何正常的用例中,一切都可以很好地工作(关闭/打开客户机会正确触发函数,锁也会按预期执行)。 需要注意的是,我的on\u disconnect函数是用完全相同的decorator和lock包装的。 我遇到的问题是,当客户端的网络适配器在物理上断开连接(正常的客户端关闭工作正常)时,我看到确实调用了on\u disconnect事件,但另一个共同例程当前持有锁。由于某些原因,事件被多次触发并最终陷入僵局。你知道吗

我已经用描述锁的状态/调用函数的打印来包装我的decorator,还为每个异步调用添加了try/catch。 似乎我的所有co例程都捕获了一个被取消的异常(我假定是由aiohttp执行的),因此一个“持有”锁的方法被取消,锁永远不会被释放。我试过用一个异步屏蔽()但行为没有改变。你知道吗

我在这里应该采用不同的异步锁方法吗?(移除锁可以完全解决问题,但可能会导致应用程序的计算部分出现未定义的行为)

更多代码示例: 实际的on\u connect和on\u disconnect事件:

    @async_synchronized('_async_mutex')
    async def on_connect(self, sid, environ):
        self._logger.info("very good log message")
        self._connected_clients_count += 1

    @async_synchronized('_async_mutex')
    async def on_disconnect(self, sid):
        self._logger.info("very good disconnect message")
        self._connected_clients_count -= 1
        await self._another_namespace_class.inform_client_disconnect(sid) # this method is wrapped with the same decorator but with a different lock

注意:另一个没有连接到同一个客户端。另外,当发生网络断开连接时,我也看不到日志消息出现(我已将日志级别设置为debug)


Tags: 函数selfinfoasyncondefconnectwith