Widziałem wiele razy w kodach ruby niezrównane File.open
połączenia
Czy możesz podać przykład? Widzę to tylko w kodzie napisanym przez początkujących, którzy nie mają „powszechnej wiedzy w większości języków programowania, że przepływ pracy z plikami jest otwarty-użyj-zamknij”.
Doświadczeni rubiniści albo jawnie zamykają swoje pliki, albo, bardziej idiomatycznie, używają formy blokowej File.open
, która automatycznie zamyka plik za Ciebie. Jego implementacja w zasadzie wygląda mniej więcej tak:
def File.open(*args, &block)
return open_with_block(*args, &block) if block_given?
open_without_block(*args)
end
def File.open_without_block(*args)
end
def File.open_with_block(*args)
yield f = open_without_block(*args)
ensure
f.close
end
Skrypty to szczególny przypadek. Skrypty zazwyczaj działają tak krótko i używają tak niewielu deskryptorów plików, że po prostu nie ma sensu ich zamykać, ponieważ system operacyjny i tak je zamknie, gdy skrypt zakończy działanie.
Czy musimy wyraźnie zamknąć?
Tak.
Jeśli tak, to dlaczego GC automatycznie się zamyka?
Ponieważ po zebraniu obiektu nie ma już możliwości zamknięcia pliku, a tym samym wyciekułoby deskryptory plików.
Zauważ, że to nie garbage collector zamyka pliki. Moduł odśmiecania pamięci po prostu wykonuje finalizatory dla obiektu, zanim go zbierze. Tak się składa, że File
klasa definiuje finalizator, który zamyka plik.
Jeśli nie, to po co?
Ponieważ zmarnowana pamięć jest tania, ale zmarnowane deskryptory plików nie. Dlatego nie ma sensu wiązać czasu życia deskryptora pliku z czasem życia jakiegoś fragmentu pamięci.
Po prostu nie można przewidzieć, kiedy będzie działać odśmiecacz. Nie można jeszcze przewidzieć, czy to będzie działać w ogóle : jeśli nigdy nie zabraknie pamięci, garbage collector nigdy nie zabraknie, dlatego finalizator nigdy nie zabraknie, więc plik nigdy nie zostanie zamknięta.