【问题标题】:Haskell Conduit and masking async exceptionsHaskell Conduit 和屏蔽异步异常
【发布时间】:2015-06-02 21:43:45
【问题描述】:

我有以下代码行,它使用 aeson 序列化 IntMap 并将 JSON 保存到磁盘,全部在子线程上:

    import Data.Aeson (encode, toJSON)
    import Data.Conduit (($$), (=$), yield)
    import qualified Data.ByteString.Lazy as BL (toStrict)
    import qualified Data.Conduit.Binary as CB (sinkFile)
    import qualified Data.Conduit.List as CL (map)

    -- ...

    forkIO . runResourceT $ yield (toJSON intMap) $$ CL.map (BL.toStrict . encode) =$ CB.sinkFile file

我想确保这段代码不会被任何异步异常中断。我担心中断可能会导致磁盘上的数据不完整/损坏。

在这种情况下,我可以做些什么来确保不受异步异常的影响?即使main想要终止,是否可以确保允许子线程完成?

谢谢!

【问题讨论】:

  • 为确保子线程完成,创建一个MVar;让子线程在其中放入一些东西,而主线程从中取出。不过,还不足以回答另一半。

标签: multithreading haskell exception asynchronous conduit


【解决方案1】:

我建议另一种技术,与 conduit 无关:

  • 创建一个新的临时文件,
  • 在那里写入您的数据,
  • fsync文件,这样就真的把所有的东西都写到了磁盘上,
  • atomically rename目标文件的临时文件;在 POSIX 系统上这很容易,因为 rename 是为它设计的,在 Windows 上 this question 应该会有所帮助。

使用这个序列,无论发生什么,目标文件要么保持完整,要么包含新数据,完全写入磁盘。如果序列由于某种原因突然中断,它只会留下一个陈旧的临时文件。

unixHaskell 库引入了fsynconly in version 2.7.1.0,但是自己添加调用很容易。请参阅 Ganeti project 中的 this module(在 BSD2 下获得许可)。特别是

foreign import ccall "fsync" fsync :: CInt -> IO CInt

fsyncFile :: FilePath -> IO ()
fsyncFile path =
    bracket (openFd path ReadOnly Nothing defaultFileFlags) closeFd callfsync
  where
    callfsync (Fd fd) = throwErrnoPathIfMinus1_ "fsyncFile" path $ fsync fd

【讨论】:

  • 感谢链接的详细回答!我不会想到采用这种方法。令人着迷的东西!
猜你喜欢
  • 2012-02-20
  • 1970-01-01
  • 2015-02-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 2018-06-11
  • 2011-12-31
相关资源
最近更新 更多