【问题标题】:Why does `mask_` neutralize `timeout`?为什么`mask_`会中和`timeout`?
【发布时间】:2011-09-13 12:55:11
【问题描述】:

我终于能够追踪到我遇到的一个奇怪的错误(至少对我而言)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 可能会导致库出现故障。

那么这是timeout 实现中的(已知)缺陷还是故意的?

【问题讨论】:

    标签: exception haskell exception-handling timeout


    【解决方案1】:

    mask_ 是做什么的?

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

    timeout 是做什么的?

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

    所以...mask_ 正在阻止timeout 传递其异常。就是这样。

    您不能使用mask 并让timeout 工作。

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

    【讨论】:

    • 对,这是不可避免的,因为超时需要计算在当前线程中运行。使用超时的库可能应该派生一个新线程来逃避掩码。
    猜你喜欢
    • 1970-01-01
    • 2023-04-04
    • 2021-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多