LINUX.ORG.RU

Некто считает, что «Don't defer Close() on writable files»

 


0

2

https://www.joeshaw.org/dont-defer-close-on-writable-files/

It’s an idiom that quickly becomes rote to Go programmers: whenever you conjure up a value that implements the io.Closer interface, after checking for errors you immediately defer its Close() method. You see this most often when making HTTP requests:

But this idiom is actually harmful for writable files because deferring a function call ignores its return value, and the Close() method can return errors. For writable files, Go programmers should avoid the defer idiom or very infrequent, maddening bugs will occur.

По ссылке все расписано и с примерами.

Осудите писателя.

В питоне есть with блок, тоже считается более предпочтительным для ввода-вывода.

menangen ★★★★★
()
Ответ на: комментарий от menangen

with это с менеджером, наверно ничего плохого не случится, интерпретатор и 100 слоёв абстракции же. к тому же столько лет разрабатывали и устраняли недочёты. а тут что?

anonymous
()

А что тут можно оспорить?

Та же история, что и с деструкторами в крестах.

anonymous
()

Ничего go-специфичного тут нет, close() всегда возвращает значение, и это всегда выбор программиста, проверять его или нет.

По-хорошему, да, если ты что-то записал в файл всегда нужно проверить что вернул close. Но это не повод не делать defer (или, в других языках, не звать close() из деструктора класса File).

Правильно - close всегда defer'ится (или зовётся из деструктора) на случай корректного освобождения ресурсов при ошибке, но после записи всего что хотели записать делается явный close() у которого проверяется код возврата. Искренне надеюсь что go не настолько недоязык, чтобы в нём при этом что-то сломалось.

slovazap ★★★★★
()
Ответ на: комментарий от anonymous

В Haskell тоже есть withFile, которая перехватывает исключения и сама закрывает файл. Наличие интерпретатора тут не причём.

В сабжевом варианте лучше бы делать defer на свою функцию, проверяющую результат close(), если golang так позволяет.

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 1)

Так-то можно сбросить содержимое файла на диск через Sync() в самом конце. И проверять его на ошибку, как и остальные операции записи в файл. А Close() спокойно оставить в defer. Автор в Update 2 то же самое и написал.

uuwaan ★★
()

Всё верно пишет. И результат `write` надо проверить, и `fsync` вызвать, и на `close` нельзя забивать, и потом ещё специальную команду для сброса кэша устройства дёрнуть. Только всё равно есть вероятность, что какой-нибудь электрон не попадёт в какую-нибудь предназначенную для него дырку, и данные не запишутся. Это называется «закон дырявых абстракций». В той или иной степени он проявляется везде, учитывать его нужно исходя из конкретной задачи.

З.Ы. Вбросил бы про «нужно ли проверять результат `malloc`».
З.З.Ы. Интересно, переводчик уже тогда хорошо знал Джоэля, или просто попал пальцем в яблочко, использовав слово «дырявый»?

Laz ★★★★★
()
Ответ на: комментарий от Laz

Не более дырявый, чем ты.

А так да, надо проверять, если важна целостность данных:

func someFunc() (err error) {
  ...
  defer func() {
    err = f.Close()
  }()
  ...
}

Если наколенный скрипт, то не обязательно.

anonymous
()

Найс проблемы у ребят ♿

ritsufag ★★★★★
()

and the Close() method can return errors.

Запомните дети, эксепшн в деструкторе - это плохо. И как автор собирается обрабатывать ситуацию «ну ты знаешь, чувак, файл закрыть не получилось»

PPP328 ★★★★★
()
Ответ на: комментарий от Laz

З.Ы. Вбросил бы про «нужно ли проверять результат `malloc`».

Нужно, потому что ты можешь запросить слишком большой кусок и когда такой кусок система не вернет можно построить обработчик так чтобы выделить место например на диске. Полезно при мат. расчетах или графике.

PPP328 ★★★★★
()
Ответ на: комментарий от anonymous
The fclose() function shall fail if:

[EAGAIN]
[CX] [Option Start] The O_NONBLOCK flag is set for the file descriptor underlying stream and the thread would be delayed in the write operation. [Option End]
[EBADF]
[CX] [Option Start] The file descriptor underlying stream is not valid. [Option End]
[EFBIG]
[CX] [Option Start] An attempt was made to write a file that exceeds the maximum file size. [Option End]
[EFBIG]
[XSI] [Option Start] An attempt was made to write a file that exceeds the process' file size limit. [Option End]
[EFBIG]
[CX] [Option Start] The file is a regular file and an attempt was made to write at or beyond the offset maximum associated with the corresponding stream. [Option End]
[EINTR]
[CX] [Option Start] The fclose() function was interrupted by a signal. [Option End]
[EIO]
[CX] [Option Start] The process is a member of a background process group attempting to write to its controlling terminal, TOSTOP is set, the process is neither ignoring nor blocking SIGTTOU, and the process group of the process is orphaned. This error may also be returned under implementation-defined conditions. [Option End]
[ENOSPC]
[CX] [Option Start] There was no free space remaining on the device containing the file. [Option End]
[EPIPE]
[CX] [Option Start] An attempt is made to write to a pipe or FIFO that is not open for reading by any process. A SIGPIPE signal shall also be sent to the thread. [Option End]
The fclose() function may fail if:

[ENXIO]
[CX] [Option Start] A request was made of a nonexistent device, or the request was outside the capabilities of the device. [Option End]

Ни один из этих кодов (ну разве кроме EAGAIN, но он не выскочит потому что никто не делает дескрипторы асинхронными) не подразумевает, что можно попробовать еще раз чтобы закрыть дескриптор. Запись в лог сообщения типа «This error may also be returned under implementation-defined conditions.» не информативно от слова никак.

PPP328 ★★★★★
()
Последнее исправление: PPP328 (всего исправлений: 1)
Ответ на: комментарий от Deleted

Нет, при чем тут вообще язык.

anonymous
()

апять кому то атомарные файловые операцыи не дают почесать ЧСВ

TooPar
()

Осудите

За что осуждать ? По мне все четко расписано, ошибки игнорить плохо.

Dred ★★★★★
()

Неплохо. Так как не писал особо на Go, не задумывался по этому поводу. Впрочем, тогда не знаю, зачем ещё нужен defer, так как видел его только для того, чтобы отпустить занятый ресурс.

Спасибо что притащил, буду знать.

Хотя на Go программировать уже особо не хочется. Хочется потыкать дальше Java и перелезть когда нибудь на C++ или Rust.

Deleted
()

Линтер гоу (не помню название) уже давно ругался на отсутствие обработки ошибок в defer Close(), походу автор его просто не использует и наступает на протухшие грабли.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.