为什么`mask_`中和`timeout`?

时间:2011-06-12 20:05:56

标签: exception haskell exception-handling timeout

我终于能够追踪到masktimeout之间令人惊讶的互动(至少对我而言)的一个奇怪的错误:

import System.Timeout
import Control.Exception

ack :: Int -> Int -> Int
ack m n | m == 0, n >= 0  = n + 1
        | m >  0, n == 0  = ack (m - 1) 1
        | m >  0, n >  0  = ack (m - 1) (ack m (n - 1))

tryack :: Int -> Int -> IO (Maybe Int)
tryack m n = timeout 100000 {- uS -} $ evaluate $ ack m n

main :: IO ()
main = do
  a <- tryack 3 11
  print a -- Nothing

  b <- mask_ $ tryack 3 11
  print b -- Just 16381 after a few seconds

这让我觉得它是一种相当“非组合”的交互,因为这意味着如果一个库内部使用timeout,那么在调用链的某个地方外部应用mask可能会导致库故障。

这是[{1}}实施中的(已知)缺陷还是故意的?

1 个答案:

答案 0 :(得分:8)

mask_做了什么?

  

执行IO计算,屏蔽异步异常。也就是说,任何尝试使用Control.Exception.throwTo在当前线程中引发异常的线程都将被阻塞,直到异步异常再次被屏蔽为止。

timeout做了什么?

  

将IO计算包装为超时,如果在n微秒(1/10 ^ 6秒)内没有可用结果,则返回Nothing。如果在超时到期之前结果可用,则返回Just a。 ...一个棘手的实现细节是如何中止IO计算的问题。这个组合器在内部依赖于异步异常。

因此...... mask_阻止timeout发布其例外情况。就是这样。

您无法使用mask并且timeout有效。

或许更好的方法是使用处理程序捕获除timeout使用的异常之外的任何内容?