如何解决如何使用threading锁定异步功能,同时可以从多个线程访问对象
我想在异步函数中使用threading.Lock()
,asyncio.Lock()
不是线程安全的,所以我不能执行with await asyncio.Lock():
。我需要使用threading.Lock()
的原因是因为该对象可以可以通过多个区域访问,因此它在Web应用程序中使用,运行它的服务器可以启动许多线程。这样做的有效方法是什么?到目前为止,我已经尝试了一个使用锁的简单函数:
1)
async def main():
with await threading.Lock():
a = 6
return a
TypeError: object _thread.lock can't be used in 'await' expression
async def main():
async with threading.Lock():
a = 1564666546
return a
AttributeError: __aexit__
解决方法
您不能将threading.Lock
传递给async with
,因为它不是为异步使用而设计的,它是一个阻塞原语。更重要的是,async with threading.Lock()
即使有效也没有任何意义,因为您将获得一个全新的锁,它将永远成功。为了使锁定有意义,您必须在多个线程之间具有 shared 锁,例如存储在对象的属性中,或以其他方式与对象相关联。该答案的其余部分将假定您在线程之间共享threading.Lock
。
由于threading.Lock
始终处于阻塞状态,因此可以从asyncio中使用它的唯一方法是在专用线程中获取它,从而中止当前协程的执行,直到获得锁为止。 run_in_executor
事件循环方法已经涵盖了此功能,您可以应用该方法:
# lock is a threading.Lock shared between threads
loop = asyncio.get_event_loop()
# Acquire the lock in a worker thread,suspending us while waiting.
await loop.run_in_executor(None,lock.acquire)
... access the object with the lock held ...
# Can release directly because release() doesn't block and a
# threading.Lock can be released from any thread.
lock.release()
您可以通过创建异步上下文管理器来使其更加美观(且异常安全):
@contextlib.asynccontextmanager
async def async_lock(lock):
loop = asyncio.get_event_loop()
await loop.run_in_executor(None,lock.acquire)
try:
yield # the lock is held
finally:
lock.release()
然后您可以按以下方式使用它:
# lock is a threading.Lock shared between threads
async with async_lock(lock):
... access the object with the lock held ...
当然,在asyncio之外,您将不会使用其中任何一个,只需直接获取锁即可:
# lock is a threading.Lock shared between threads
with lock:
... access the object ...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。