2012-05-29 12 views
8

Mi primera impresión de readFile fue una compensación entre su comodidad y la posibilidad de que deje los descriptores de archivos abiertos más de lo necesario, sin posibilidad de cerrarlos. Como un experimento que probé el siguiente programa (muy práctico), pensando que podría ahogarse al tratar de mantener un millar de descriptores de archivo abiertos:¿Cuándo es mejor cerrar explícitamente los identificadores de archivo?

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

Pero lo que realmente hace un buen trabajo de recuperación de descriptores de archivos; el recuento nunca supera 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 

¿Cómo va esto? ¿Es solo que los valores de contents están recibiendo GC'd, y con ellos los descriptores de archivos que ya no se referencian? ¿O hay algún mecanismo separado para administrar los recursos del descriptor de archivos? Cualquiera que sea el mecanismo, parece funcionar bastante bien: ¿cómo puede saber cuándo es mejor usar hClose explícitamente?

+1

Creo que es solo el GC el que está causando que se cierren los descriptores de archivos. –

+0

En general, es mejor utilizar mecanismos que aseguren el manejo de recursos determinísticos (que no sean la memoria), en Haskell que sería 'bracket '. No confíe en GC con archivos para algo más que un simple caso. El soporte –

+1

solo tendrá sentido con un IO estricto; de lo contrario, el efecto puede filtrarse a través de los datos vagos. –

Respuesta

8

Es mejor que cierre los recursos de forma explícita, solo cuando tenga alguna restricción de recursos de bajo nivel que pueda aplicar manualmente.

Los casos a considerar:

  • recursos aquired través perezoso IO: debe utilizar el GC para liberar el recurso
  • estricta IO: puede cerrar manualmente una vez que se lee de entrada; o utilice un combinador de horquillado (por ejemplo, finally o bracket)
  • IO incremental (conductos, iteraciones): deje que el marco lo cierre por usted.
7

El Haddock docs for System.IO tiene esto que decir:

GHC nota: un mango se cerrará automáticamente cuando el recolector de basura detecta que se ha convertido en no referenciado por el programa. Sin embargo, confiar en este comportamiento generalmente no se recomienda: el recolector de basura es impredecible. Si es posible, use un hClose explícito para cerrar Handles cuando ya no sean necesarios. GHC actualmente no intenta liberar los descriptores de archivos cuando se han agotado, es su responsabilidad asegurarse de que esto no suceda.

Cuestiones relacionadas