2017-02-10 39 views
11

在Haskell中,我們有異步異常;我們可以用throwTo提出任何例外在另一個線程:Python是否與Haskell的'mask'或'bracket'函數等價?

throwTo :: Exception e => ThreadId -> e -> IO() 

throwTo提出的目標線程的任意異常(僅GHC)。

爲了能夠與像「收購之後總是會釋放鎖」保證編寫的代碼,我們必須mask運行代碼,其中在計算阻塞異步異常可能只收到:

mask :: ((forall a. IO a -> IO a) -> IO b) -> IO b 

使用異步異常執行IO計算屏蔽了。也就是說,任何嘗試在throwTo當前線程中引發異常的線程都將被阻塞,直到異步異常再次取消屏蔽。

和更強的uninterruptibleMask在異步異常情況將不是一個蒙面的計算過程中引發的在所有

uninterruptibleMask :: ((forall a. IO a -> IO a) -> IO b) -> IO b 

mask,但蒙面計算是不可中斷

掩蔽用於實現更高層次的抽象,如bracket

bracket 
    :: IO a   -- computation to run first ("acquire resource") 
    -> (a -> IO b) -- computation to run last ("release resource") 
    -> (a -> IO c) -- computation to run in-between 
    -> IO c   -- returns the value from the in-between computation 

當你想要獲取的資源,做一些工作吧,然後釋放資源,它是用bracket,因爲bracket將安裝必要的異常處理程序來釋放資源是一個好主意在計算過程中發生異常的情況下。如果發生異常,則bracket將重新引發異常(執行發佈後)。

如果我理解正確,Python有異步異常的(小於一般)的形式,最顯着的表現是KeyboardInterrupt

當用戶點擊中斷鍵提高(通常控制 - C刪除)。在執行期間,會定期檢查中斷。

的文檔是不精確的約當「檢查有無中斷」可能發生,但它似乎暗示着KeyboardInterrupt可以提高在程序執行任何點。因此,看起來,Python的異步異常具有保持正確性的所有相同的微妙困難。

例如,請考慮這樣一個規律:

x = None 
try: 
    x = acquire() 
    do_something(x) # (1) 
finally: 
    if x is not None: # (2) 
     release(x) 

如果有任何異常被(1)提高,那麼我們放心,finally塊的內容將被執行。但是如果KeyboardInterrupt(2)期間會發生什麼?

在沒有掩蓋它們的情況下,在存在asyc異常的情況下保證資源清理似乎根本不可能。有沒有這方面的設施,還是我們依靠ostrich algorithm

+1

我想你幾乎必須爲Ctrl-C安裝自己的信號處理程序,如果你想這樣做。 – user2357112

回答

3

這是上下文管理員的用途。

with acquire() as x: 
    do_something(x) 

acquire返回一個對象,其類型定義了一個__enter__方法,它返回勢必x值,和__exit__方法,該方法是在with語句結束不管該語句是如何退出執行。

+2

如果發生進一步異常,可以中斷'__exit__'方法嗎? –

+0

@DanielWagner當我編寫Python時,我的模糊記憶:在__exit__中出現的異常中斷正常的__exit__方法;提示'__exit__'塊的異常將成爲後來的異常'__cause__'。 –

+0

您必須自己安裝一個信號處理程序,但'__exit__'方法爲此提供了一個方便的範圍:在輸入方法時立即安裝處理程序,並在退出之前恢復之前的處理程序。 – chepner

相關問題