我正在尝试使用 Haskell 构建并发且健壮的代码,建议我使用安全异常和异步库。但是,我很难理解如何处理动作中引发的非致命错误async
。
例如,如果有一个简单的循环每隔n秒检查一次网络资源,那么使用会导致在单独线程中引发异常的cancel
函数来停止它是有意义的。AsyncCancelled
当然,也有可能IOError
由于网络中断或其他问题而从线程内抛出 an 。根据异常的类型及其包含的数据,我想控制单独的线程是否忽略异常、执行某些操作、停止或在主线程中引发异常。
使用安全异常库,唯一能够做到这一点的函数是catchAsync
和其他类似的函数,它们在文档中被标记为危险。除此之外,waitCatch
异步库中有,但是当我尝试提取时该fromException
函数总是返回:Nothing
IOError
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Concurrent.Async
import Control.Concurrent hiding (throwTo)
import Control.Exception.Safe
import Control.Monad
import System.IO
import System.IO.Error hiding (catchIOError)
main = do
hSetBuffering stdin NoBuffering
putStrLn "Press any key to continue..."
a <- async runLoop
async $ hWaitForInput stdin (-1) *>
throwTo (asyncThreadId a) (userError "error")
waitCatch a >>= either handler nothing
where
printThenWait i = putStr (show i ++ " ") *> threadDelay 1000000
runLoop = sequence_ $ printThenWait <$> [1..]
nothing _ = pure ()
handler e
| Just (e' :: IOError) <- fromException e =
putStrLn "It's an IOError!"
| (Nothing :: Maybe IOError) <- fromException e =
putStrLn "We got Nothing!"
我对从异步异常中恢复的危险感到有些困惑,尤其是当标准函数(例如cancel
导致它们被抛出)时,我不知道在使用这两个库时推荐的处理它们的方法是什么。这是一个值得推荐的例子,catchAsync
还是有另一种方法来处理我没有发现的这些类型的情况?