簡體   English   中英

如何使用 threading.Lock 在異步 function 而 object 可以從多個線程訪問

[英]How to use threading.Lock in async function while object can be accessed from multiple thread

我想在異步 function 中使用threading.Lock()asyncio.Lock()不是線程安全的,所以我不能with await asyncio.Lock(): 我需要使用threading.Lock()的原因是因為這個 object可以被多個線程訪問,因此它用於 web 應用程序,運行它的服務器可以啟動許多線程。 這樣做的有效方法是什么? 到目前為止,我已經嘗試了一個使用鎖的簡單 function:

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()沒有意義,即使它確實有效,因為您將獲得一個全新的鎖,這總是會成功。 為了使鎖定有意義,您必須在多個線程之間共享一個鎖,例如存儲在 object 的屬性中,或以另一種方式與 object 關聯。 此答案的 rest 將假定您有一個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 ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM