什么时候显式关闭文件句柄更好?

时间:2012-05-29 21:08:45

标签: haskell

我对readFile的第一印象是它的便利性与文件描述符打开时间超过需要的可能性之间的权衡,无法关闭它们。作为一个实验,我尝试了以下(非常实用的)程序,认为它可能会因为试图维护一千个打开的文件描述符而窒息:

main = do
  mapM_ (\idx -> readIt) [1..1000]
  where readIt = do
          contents <- readFile "/etc/passwd"
          putChar $ head contents

但它实际上在回收文件描述符方面做得非常好;伯爵从未超过70左右:

open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 4
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 5
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 6
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 7
...
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 65
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 66
close(3)                                = 0
close(4)                                = 0
close(5)                                = 0
...
close(54)                               = 0
close(55)                               = 0
close(56)                               = 0
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 3
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 4

这是怎么回事?只是contents的值正在获得GC,并且它们是不再引用的文件描述符吗?或者是否有一些单独的机制来管理文件描述符资源?无论机制是什么,它似乎运作良好 - 你怎么知道什么时候最好明确地使用hClose

2 个答案:

答案 0 :(得分:8)

最好自己明确地关闭资源,只有当你有一些可以手动实施的低级别资源约束时。

需要考虑的案例:

  • 通过懒惰IO获取的资源:必须使用GC释放资源
  • 严格IO:读取输入后可以手动关闭;或使用包围组合器(例如finallybracket
  • 增量IO(管道,迭代):让框架为您关闭它。

答案 1 :(得分:7)

Haddock docs for System.IO有这样说:

  

GHC注意:当垃圾收集器检测到它已被程序取消引用时,句柄将自动关闭。但是,通常不建议依赖此行为:垃圾收集器是不可预测的。如果可能,使用显式hClose在不再需要时关闭Handles。 GHC目前没有尝试在文件描述符用完时释放它们,你有责任确保不会发生这种情况。