如何使用safe-exceptions库捕获异步异常?

时间:2018-05-29 09:58:31

标签: multithreading haskell exception-handling thread-exceptions

我正在尝试使用Haskell构建并发且健壮的代码,建议我使用safe-exceptionsasync库。但是,我很难理解如何处理async动作中抛出的非致命错误。

例如,如果有一个简单的循环每隔 n 秒检查一个网络资源,那么使用导致{{cancel函数的AsyncCancelled函数来停止它是有意义的。 1}}在单独的线程中抛出的异常。当然,由于网络出现故障或其他一些问题,也有可能从线程中抛出IOError。根据异常的类型及其包含的数据,我想控制单独的线程是否忽略异常,执行某些操作,停止或引发主线程中的异常。

使用安全异常库,能够执行此操作的唯一功能是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 的实例,还是有另一种方法来处理我未发现的这类情况?

1 个答案:

答案 0 :(得分:1)

请注意,((window) => { window.lib = { LibClassBase: class {} LibClass1: class extends LibClassBase {} } })(window) Control.Exception.Safe.throwToAsyncExceptionWrapper IOError wraps个同步异常是同步。 (我不知道为什么这种包装是必要的,你不应该异步地抛出异步异常。)

要使代码正常工作,您应该抓住AsyncExceptionWrapper或使用Control.Exception.throwTo。但实际上我并没有完全明白你想要做什么,很可能是你过于复杂的事情。