[英]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.