在Haskell中,我们有异步异常;我们可以使用throwTo
在另一个线程中引发任何异常:
throwTo :: Exception e => ThreadId -> e -> IO ()
throwTo
在目标线程中引发任意异常(仅限GHC)。
为了能够使用"这样的保证编写代码,在获取它之后将始终释放锁定#34;我们有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
类似,但屏蔽的计算不可中断
Masking用于实现更高级别的抽象,例如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
:
当用户按下中断键时(通常 Control - 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?
答案 0 :(得分:3)
这就是上下文管理器的用途。
with acquire() as x:
do_something(x)
acquire
返回一个对象,其类型定义__enter__
方法,返回绑定到x
的值,以及__exit__
方法,该方法在结束时执行with
语句,无论语句如何退出。