2012-05-29 10 views
8

La mia prima impressione di readFile era un compromesso tra la sua convenienza e la possibilità che esso lasciasse i descrittori di file aperti più a lungo del necessario, senza possibilità di chiuderli. Come esperimento ho provato il seguente programma (molto pratico), pensando che potesse soffocare cercando di mantenere un migliaio di descrittori di file aperti:Quando è meglio chiudere esplicitamente gli handle di file?

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

ma in realtà fa un buon lavoro di bonifica descrittori di file; il conto non arriva mai sopra 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 

Come sta succedendo? È solo che i valori di contents stanno ricevendo GC e con essi i descrittori di file non più indirizzati? O esiste un meccanismo separato per la gestione delle risorse dei descrittori di file? Qualunque sia il meccanismo, sembra che funzioni abbastanza bene: come puoi sapere quando è meglio usare hClose esplicitamente?

+1

Credo che sia solo il GC a causare la chiusura dei descrittori di file. –

+0

In generale, è meglio usare meccanismi che assicurino una gestione deterministica delle risorse (diversa dalla memoria), in Haskell sarebbe 'parentesi'. Non fidarti di GC con i file per qualcosa di più di un semplice caso. La staffa –

+1

ha senso solo con un IO preciso, altrimenti l'effetto può fuoriuscire attraverso i dati pigri. –

risposta

8

È preferibile chiudere esplicitamente le risorse da soli, solo quando si dispone di un vincolo di risorse di basso livello che è possibile applicare manualmente.

I casi da considerare:

  • risorse aquired via pigro IO: deve utilizzare il GC per liberare la risorsa
  • rigorosa IO: può chiudere manualmente una volta di ingresso viene letta; oppure utilizzare un combinatore di bracketing (ad esempio finally o bracket)
  • I/O incrementale (conduit, iterate): lasciare che il framework lo richieda per te.
7

Il Haddock docs for System.IO hanno a dire:

GHC nota: una maniglia sarà chiuso automaticamente quando il garbage collector rileva che è diventato referenziata dal programma. Tuttavia, non è consigliabile fare affidamento su questo comportamento: il garbage collector è imprevedibile. Se possibile, usa un hClose esplicito per chiudere Handles quando non sono più necessari. GHC attualmente non tenta di liberare i descrittori di file quando sono esauriti, è tua responsabilità assicurarti che ciò non avvenga.

Problemi correlati