使用名称创建异步锁
Create asyncio lock with name
我们能否以某种方式使用 asyncio 创建类似于 Redis 命名锁行为方式的东西?
在 Redis 中我们可以使用 lock with key,这样如果你改变密钥,它就会改变锁。
这样我们就可以为不同的钥匙使用不同的锁,这将加快速度。
with r.lock('my_lock'):
# ...
我们可以使用 asyncio
做类似的事情吗?谢谢!
使用函数式方法和字典,您可以执行如下操作:
import asyncio
from contextlib import asynccontextmanager # python 3.7+
from random import randint
locks = {}
@asynccontextmanager
async def get_lock(id):
if not locks.get(id):
locks[id] = asyncio.Lock()
async with locks[id]:
yield
if len(locks[id]._waiters) == 0 and is_obsolete(id):
del locks[id]
print(len(locks))
def is_obsolete(id):
return True # whatever test you need
async def main():
tasks = []
for _ in range(100):
id = randint(0, 10)
tasks.append(asyncio.create_task(do_task(id)))
await asyncio.sleep(0.01)
await asyncio.gather(*[task for task in tasks if not task.done()])
async def do_task(id):
async with get_lock(id):
await asyncio.sleep(randint(0, 10) / 10)
asyncio.run(main())
一旦没有剩余的等待任务和可能基于您的应用程序的另一个条件(比如资源仍然存在),锁就会被移除。
这应该适用于任何可哈希 id
。例如 pathlib.Path
很好。
我不知道它对您来说需要多高的效率。嵌套的上下文管理器可能是一个无赖。我想替代方案是 subclass asyncio.Lock
覆盖 __aexit__
并创建某种管理器 class 但我认为这会更冗长。
我们能否以某种方式使用 asyncio 创建类似于 Redis 命名锁行为方式的东西?
在 Redis 中我们可以使用 lock with key,这样如果你改变密钥,它就会改变锁。
这样我们就可以为不同的钥匙使用不同的锁,这将加快速度。
with r.lock('my_lock'):
# ...
我们可以使用 asyncio
做类似的事情吗?谢谢!
使用函数式方法和字典,您可以执行如下操作:
import asyncio
from contextlib import asynccontextmanager # python 3.7+
from random import randint
locks = {}
@asynccontextmanager
async def get_lock(id):
if not locks.get(id):
locks[id] = asyncio.Lock()
async with locks[id]:
yield
if len(locks[id]._waiters) == 0 and is_obsolete(id):
del locks[id]
print(len(locks))
def is_obsolete(id):
return True # whatever test you need
async def main():
tasks = []
for _ in range(100):
id = randint(0, 10)
tasks.append(asyncio.create_task(do_task(id)))
await asyncio.sleep(0.01)
await asyncio.gather(*[task for task in tasks if not task.done()])
async def do_task(id):
async with get_lock(id):
await asyncio.sleep(randint(0, 10) / 10)
asyncio.run(main())
一旦没有剩余的等待任务和可能基于您的应用程序的另一个条件(比如资源仍然存在),锁就会被移除。
这应该适用于任何可哈希 id
。例如 pathlib.Path
很好。
我不知道它对您来说需要多高的效率。嵌套的上下文管理器可能是一个无赖。我想替代方案是 subclass asyncio.Lock
覆盖 __aexit__
并创建某种管理器 class 但我认为这会更冗长。