繁体   English   中英

如何在 asyncio 中安全地从列表中删除值

[英]how to remove value from list safely in asyncio

有一个全局list来存储数据。 不同的异步函数可能会从中addremove值。

例子:

a = [] # List[Connection]

async def foo():
    for v in a:
        await v.send('msg')
       

async def bar():
    await SomeAsyncFunc()
    a.pop(0)

foobar都会放弃控制权让其他协程运行,因此在foo中,从列表中删除值是不安全的。

以下示例显示了如何为此使用锁:

创建连接管理器:

import asyncio

class ConnectionsManager:
    def __init__(self, timeout=5):
        self.timeout = timeout
        self._lock = asyncio.Lock()
        self._connections = []
    
    async def __aenter__(self):
        await asyncio.wait_for(self._lock.acquire(), timeout=self.timeout)
        return self._connections

    async def __aexit__(self, *exc):
        self._lock.release()

超时是一种通过循环等待来解决错误的安全措施。

管理器可以按如下方式使用:

async def foo():
    for _ in range(10):
        async with cm as connections:
            # do stuff with connection
            await asyncio.sleep(0.25)
            connections.append('foo')
        
async def bar():
    for _ in range(5):
        async with cm as connections:
            # do stuff with connection
            await asyncio.sleep(0.5)
            if len(connections) > 1:
                connections.pop()
            else:
                connections.append('bar')

cm = ConnectionsManager()
t1 = asyncio.create_task(foo())
t2 = asyncio.create_task(bar())
await t1
await t2
async with cm as connections:
    print(connections)

请注意,您也可以在此处更明确地使用连接:

async def foo(cm):
    ...
async def bar(cm):
    ...

只是为了发表评论,为什么与全局变量相比,显式如此有益。 在某些时候,您可能需要为代码编写单元测试,您需要指定函数/方法的所有输入。 忘记函数隐式输入的条件(使用的全局变量)很容易导致未经测试的状态。 例如,您的bar协程需要列表a中的一个元素,如果它为空,它将中断。 大多数时候它可能会做正确的事情,但有一天在生产中......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM