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

Haskell 什么时候显式关闭文件句柄更好?,haskell,Haskell,我对readFile的第一印象是,它的方便性和让文件描述符打开的时间比需要的时间长而无法关闭的可能性之间存在权衡。作为一个实验,我尝试了以下(非常实用的)程序,认为它可能会因为试图维护一千个打开的文件描述符而窒息: main = do mapM_ (\idx -> readIt) [1..1000] where readIt = do contents <- readFile "/etc/passwd" putChar $ head c

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

main = do
  mapM_ (\idx -> readIt) [1..1000]
  where readIt = do
          contents <- readFile "/etc/passwd"
          putChar $ head contents
这是怎么发生的?仅仅是
内容的值
得到了GC'd,并且不再引用文件描述符吗?或者是否有一些单独的机制来管理文件描述符资源?无论该机制是什么,它似乎工作得很好-您如何知道何时最好明确使用
hClose

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


最好是自己显式关闭资源,只有当您有一些可以手动执行的低级资源约束时

需要考虑的案例:

  • 通过惰性IO获取的资源:必须使用GC释放资源
  • 严格IO:读取输入后可手动关闭;或使用括号组合符(例如,
    finally
    括号
  • 增量IO(管道、迭代对象):让框架为您关闭它

我相信正是GC导致文件描述符关闭。一般来说,最好使用确保确定性资源(而不是内存)处理的机制,在Haskell中,这应该是
括号中的
。除了简单的情况外,不要将文件信任给GC。括号只适用于严格的IO,否则效果可能会通过惰性数据泄漏。
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