multithreading - 如何使用安全异常库捕获异步异常?
问题描述
我正在尝试使用 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
还是有另一种方法来处理我没有发现的这些类型的情况?
解决方案
请注意,将同步异常Control.Exception.Safe.throwTo
包装AsyncExceptionWrapper
到, 并且IOError
是同步的。(我不知道为什么这种包装是必要的,无论如何你都不应该异步抛出同步异常。)
要使您的代码正常工作,您应该捕获AsyncExceptionWrapper
或使用Control.Exception.throwTo
. 但实际上我并不完全理解你想要做什么,很可能你把事情复杂化了。
推荐阅读
- javascript - 将数据从前端发送到后端到前端
- neo4j - 将 WHERE IN 与 COLLECT 一起使用,其中收集正在创建地图
- php - 我只是无法删除我在 Laravel 中的一个用户地址
- angularjs - 修改Highcharts sankey-diagram连接线的长度
- java - 当我们执行 Modelservice.Save() 时,Hybris 做了什么?
- ios - 除非快速选择所有单元格,否则限制表格视图
- java - 什么样的权限设置可能会阻止 Windows 机器上的用户更新他的 Java 部署信任库
- encoding - 仅带有 P 帧的 x264 编码视频和用于 I 帧的不同视频
- gradle - 如何导入其他gradle?
- javascript - 无法在 javascript 中正确更改父元素