寫過多線程程序的人確定對各類鎖很熟悉,尤爲是下面這種代碼python
def lock_usage: lock.Lock() if(...) : lock.Unlock() return lock.Unlock() return
了避免形成死鎖,須要在每一個return語句以前都釋放鎖。像上面的代碼中,若是代碼的執行路徑不少,代碼中就會包含大量的unlock語句,代碼混亂仍是小事兒,若是萬一忘掉了unlock,就是個潛在的危險。除了鎖以外,包括文件描述符的關閉等涉及到資源釋放的操做都會有這種問題。
爲了解決內存泄漏的內存問題,現代的編程語言提供了垃圾回收機制。一樣爲了解決上面這種有限資源的釋放問題,不少語言都提供了一些語法特性。Python有with語句,C#有using,Go有defer。 先看解決這種問題的常規作法,使用finally編程
try: lock.Lock() ...... except: prcess_except() finally: lock.Unlock
這麼寫使得代碼很亂,尤爲是當......處的代碼也包含有相似代碼時,會使得代碼更加混亂。再來看使用with語句後的代碼多線程
class LockContext(object): __init__(self, lock): self.lock = lock __enter__(self): self.Lock() __exit__(self, type, value, traceback): if type != None: process_except() self.Unlock() return false with LockContext(lock) as lock: .......
這樣寫出來,代碼量雖然差很少,可是結構清晰了不少。在上面的代碼中__init__中的賦值是可選的,只要保證可以訪問到所需的變量就可。Python中的with語句中要求對象實現__enter__和__exit__函數。調用with語句時,會先分析該語句,執行__enter__函數,而後在當前suite退出時,會調用__exit__函數。__exit__函數中除了能夠作釋放資源的操做以外,同時也是異常處理的地方。若是當前suite正常退出,沒有拋出任何異常,__exit__的幾個參數均爲None。不然,則將此異常的type、value、traceback做爲參數傳遞給__exit__函數,同時,若是__exit__返回false,此異常會再次拋出,上一級代碼suite能夠繼續處理,若是__exit__返回true,那麼此異常就不會被再次拋出了編程語言