【问题标题】:What is the correct way of cleaning up resources using ResourceT?使用 ResourceT 清理资源的正确方法是什么?
【发布时间】:2014-05-21 23:46:58
【问题描述】:

我一直在玩 conduit-extra 的 UNIX 包,它基本上允许使用 UNIX 域套接字轻松创建服务器,特别是使用 runUnixServer funciton

问题是函数存在后并没有清理socket文件,这意味着需要手动清理。这是一个简单的例子,它基本上创建了一个回显服务器。

main :: IO ()
main = do
  let settings = serverSettings "foobar.sock"
  runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))

我用谷歌搜索了一下,发现这里处理资源的正确方法是使用resourcet 包。虽然问题是资源中的大多数 API 都希望我自己分配资源,但 runUnixSever 的情况并非如此,它不会返回任何内容。

一开始我以为可以用register,注册一个删除文件的函数,比如下面

main :: IO ()
main = runResourceT $ do
  register $ removeLink "foobar.sock"
  let settings = serverSettings "foobar.sock"
  liftIO $ runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))

但这种方法存在问题,至少就allocate 的文档而言:

这几乎与调用分配然后注册释放操作相同,但是这可以正确处理异步异常的屏蔽。

这是否意味着register 本身不处理异步异常?如果是这样,当runUnixServer 生成的处理程序之一(文档说它为每个客户端生成一个线程)引发错误时,这是​​否会成为问题?

我想出的第三个也是最后一个解决方案是使用allocate,以确保正确处理异步异常(我不确定在这种情况下是否真的有必要)。

main :: IO ()
main = runResourceT $ do
  allocate (return 1) (const $ removeLink "foobar.sock")
  let settings = serverSettings "foobar.sock"
  liftIO $ runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))

但这真的是最好的解决方案吗?因为我正在创建一个我永远不会使用 (return 1) 的值,然后使用 const 函数在终结器中忽略该值。

【问题讨论】:

    标签: sockets haskell resources conduit


    【解决方案1】:

    在解决resourcet 问题之前:

    1. 在这种情况下不需要resourcet。您可以只使用 finally 函数来完成类似的事情,例如runUnixServer settings (\ad -> ...)finallyremoveLink "foobar.sock".
    2. 这实际上看起来像是有问题的行为。管道中普遍接受的模式是,如果您分配资源,则您负责清理它。 unix socket 代码不是我写的,所以作者在这里做的不同可能是有原因的。但值得打开一个错误报告。

    也就是说,您使用register 的初始代码很好。我看到的唯一问题是如果在创建 foobar.sock 之前引发异常,尽管我的 finally 解决方案也容易受到此影响。

    关于 allocate vs register 的注释与如下代码有关:

    handle <- openFile fp ReadMode
    register $ hClose handle
    

    此代码容易受到在 openFileregister 调用之间引发的异步异常的影响。由于您没有分配这样的资源,register 很好。

    【讨论】:

    • 感谢您的快速回复!
    猜你喜欢
    • 2018-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-28
    • 2019-04-14
    • 1970-01-01
    • 2019-08-29
    相关资源
    最近更新 更多