首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在从多个线程访问对象时在异步函数中使用threading.Lock

如何在从多个线程访问对象时在异步函数中使用threading.Lock
EN

Stack Overflow用户
提问于 2020-08-14 21:49:17
回答 1查看 2.6K关注 0票数 1

我想在异步函数中使用threading.Lock()asyncio.Lock()不是线程安全的,所以不能执行with await asyncio.Lock():。我需要使用threading.Lock()的原因是因为这个对象可能被多个踏板访问,因此它在web应用程序中使用,运行它的服务器可以旋转许多线程。这样做的有效方法是什么?到目前为止,我尝试了一个使用锁的简单函数:

1)

代码语言:javascript
运行
复制
async def main():
    with await threading.Lock():
        a = 6
    return a

TypeError: object _thread.lock can't be used in 'await' expression

代码语言:javascript
运行
复制
async def main():
    async with threading.Lock():
            a = 1564666546
    return a

AttributeError: __aexit__
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-15 10:50:44

您不能将threading.Lock传递给async with,因为它不是为异步使用而设计的,它是一个阻塞基元。更重要的是,async with threading.Lock()没有意义,即使它确实有效,因为您将获得一个全新的锁,这将永远成功。为了使锁定有意义,您必须在多个线程之间共享一个锁,例如存储在对象的属性中,或者以另一种方式与对象关联。这个答案的其余部分将假设您在线程之间共享一个threading.Lock

由于threading.Lock总是阻塞,所以您可以从异步中使用它的唯一方法是在一个专用线程中获取它,在获得锁之前暂停当前协同线的执行。run_in_executor事件循环方法已经涵盖了此功能,您可以应用该方法:

代码语言:javascript
运行
复制
_pool = concurrent.futures.ThreadPoolExecutor()

async def work(lock, other_args...):
    # 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(_pool, 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()

通过创建异步上下文管理器,您可以更优雅地使用它(以及异常安全):

代码语言:javascript
运行
复制
_pool = concurrent.futures.ThreadPoolExecutor()

@contextlib.asynccontextmanager
async def async_lock(lock):
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(_pool, lock.acquire)
    try:
        yield  # the lock is held
    finally:
        lock.release()

然后您可以按以下方式使用它:

代码语言:javascript
运行
复制
# lock is a threading.Lock shared between threads
async with async_lock(lock):
    ... access the object with the lock held ...

当然,在异步之外,您不会使用其中的任何一个,您只需直接获取锁:

代码语言:javascript
运行
复制
# lock is a threading.Lock shared between threads
with lock:
   ... access the object ...

注意,我们使用一个单独的线程池,而不是将None传递给run_in_executor()来重用默认池。这是为了避免在持有锁的函数本身需要访问线程池以供其他run_in_executor()使用的情况下出现死锁。通过保持线程池的私有性,我们避免了其他人通过使用同一个池而导致死锁的可能性。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63420413

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档