Engineering · 1 min read
Python with lock:就算拋例外,鎖也一定會放
手動 acquire 與 release 少了 try/finally,一次例外就會讓鎖永遠不放。Python 的 with lock 語法糖能保證例外時鎖依然釋放。
多執行緒下的 Python
with lock: 保證例外時也會釋放鎖
手動 acquire()/release() 少了 try/finally,body 一拋錯,鎖就永遠放不掉,之後每個來取鎖的都卡住,變成永久死鎖。
with lock: 其實是 acquire + try/finally release 的語法糖:
with self._login_lock: # lock.acquire()
... # try: ... finally: lock.release()
區塊一結束,release() 一定會執行,連 body 拋例外時也一樣。
拿真實情境來說:login() 的臨界區會呼叫 session.post() + raise_for_status(),兩者都可能拋錯。改用 with self._login_lock: 就能確保網路一出錯鎖也會釋放,不會讓一次失敗的登入卡死該 worker 之後所有登入。
Python threading library 的同步原語全都吃 with:Lock、RLock、Condition、Semaphore、BoundedSemaphore。能用 with 就用。
鎖的釋放不該依賴 happy path。用
with,把它交給finally。
參考來源:
- https://docs.python.org/3/library/threading.html
- https://superfastpython.com/thread-context-manager/
Related: 參見雙重檢查鎖定的兩個檢查各司其職拆解、先做完再發佈的安全發佈模式,或回到讓 login 執行緒安全的四筆學費總覽。