Почему `mask_` нейтрализует` timeout`? - PullRequest
4 голосов
/ 13 июня 2011

Мне наконец удалось отследить странную ошибку, с которой я столкнулся, вплоть до (по крайней мере, для меня) удивительного взаимодействия между mask и timeout:

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 или это умышленно?

1 Ответ

8 голосов
/ 13 июня 2011

Что делает mask_?

Выполняет вычисление ввода-вывода с замаскированными асинхронными исключениями.То есть любой поток, который пытается вызвать исключение в текущем потоке с помощью Control.Exception.throwTo, будет заблокирован до тех пор, пока асинхронные исключения не будут снова демаскированы.

И что означает timeout do?

Обернуть вычисление ввода-вывода в тайм-аут и вернуть ничего, если результат не доступен в течение n микросекунд (1/10 ^ 6 секунд). В случае, если результат доступен до истечения времени ожиданияистекает, просто возвращается.... Сложной реализацией является вопрос о том, как прервать вычисление ввода-вывода.Этот комбинатор внутренне использует асинхронные исключения.

Итак ... mask_ не позволяет timeout доставлять свои исключения.Вот только как это.

Вы просто не можете использовать mask и иметь timeout работу.

Возможно, лучшим подходом было бы использование обработчика для отлова чего-либо, кроме исключения, которое использует timeout?

...