【问题标题】:Does Python have an equivalent to Haskell's 'mask' or 'bracket' functions?Python 是否有等效于 Haskell 的“掩码”或“括号”函数?
【发布时间】:2017-02-10 20:09:59
【问题描述】:

在 Haskell 中,我们有异步异常;我们可以使用throwTo 在另一个线程中引发任何异常:

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

当用户点击中断键时触发(通常是 Control-CDelete)。在执行过程中,会定期检查中断。

文档对何时可能发生“检查中断”并不精确,但它似乎暗示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

【问题讨论】:

  • 如果你想这样做,我认为你几乎必须为 Ctrl-C 安装自己的信号处理程序。

标签: python haskell asynchronous exception-handling


【解决方案1】:

这就是上下文管理器的用途。

with acquire() as x:
    do_something(x)

acquire 返回一个对象,其类型定义了一个__enter__ 方法,该方法返回绑定到x 的值,以及一个__exit__ 方法,该方法在with 语句的末尾执行,不管如何该语句已退出。

【讨论】:

  • 如果再次发生异常,是否可以中断__exit__ 方法?
  • @DanielWagner 我写 Python 时的模糊记忆:__exit__ 期间发生的异常照常中断__exit__ 方法;提示__exit__ 块的异常变成了后面异常的__cause__
  • 您必须自己安装信号处理程序,但__exit__ 方法为此提供了一个方便的范围:在进入该方法后立即安装该处理程序,并在退出之前恢复之前的处理程序。
  • 同样的问题:信号处理程序的执行可以被另一个信号中断吗?
猜你喜欢
  • 1970-01-01
  • 2012-08-26
  • 2017-01-21
  • 2019-09-17
  • 2011-06-28
  • 1970-01-01
  • 2012-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多