Как мне добавить буферизацию для gzip-писателя?
Я заметил, что пакет gzip использует bufio
внутренне для чтения сжатых файлов, но не для их записи. Я знаю, что буферизация важна для производительности ввода-вывода, так каков правильный способ буферизации gzip-писателя?
// ignoring error handling for this example
outFile, _ := os.Create("output.gz")
// Alternative 1 - bufio.Writer wraps gzip.Writer
gzipWriter, _ := gzip.NewWriter(outFile)
writer, _ := bufio.NewWriter(gzipWriter)
// Alternative 2 - gzip.Writer wraps bufio.Writer
writer, _ := bufio.NewWriter(outFile)
gzipWriter, _ := gzip.NewWriter(writer)
// Alternative 3 - replace bufio with bytes.Buffer
buf := bytes.NewBuffer()
gzipWriter, _ := gzip.NewWriter(&buf)
Кроме того, нужно ли Flush() пишущий gzip или bufio writer (или оба) перед его закрытием, или закрытие автоматически сбрасывает пишущий?
ОБНОВЛЕНИЕ: теперь я понимаю, что чтение и запись буферизируются с помощью gzip. Так что буферизация gzip.Writer
действительно двойная буферизация. @peterSO считает, что это избыточно. @ Стивен Вайнберг полагает, что двойная буферизация может уменьшить количество системных вызовов, но, безусловно, предлагает сравнительный анализ.
1 ответ
Правильный способ использования bufio - обернуть писателя большими накладными расходами для каждого вызова записи. Это касается любого писателя, которому требуются системные вызовы. В этом случае ваш outFile - это файл ОС, а каждая запись - это системный вызов.
outFile, err := os.Create("output.gz")
defer outFile.Close()
buf := bufio.NewWriter(outFile)
defer buf.Flush()
gz := gzip.NewWriter(buf)
defer gz.Close()
io.Copy(gz, src)
return
В этом случае мы группируем записи в outFile с помощью bufio, чтобы избежать ненужных системных вызовов. Порядок src -> gzip -> buffer -> file.
Теперь, когда мы заканчиваем писать, у нас есть несколько буферов, которые нужно закрыть. Нам нужно сообщить gzip, что мы закончили, чтобы он мог очистить свои буферы и записать окончательную информацию в буфер. Затем мы должны сообщить bufio.Writer, что все готово, чтобы он мог записать свои внутренние буферы, которые он сохранял для следующей пакетной записи. Наконец, нам нужно сообщить ОС, что мы закончили с файлом.
Это разрушение происходит в порядке, обратном созданию, поэтому мы можем использовать отсрочку, чтобы упростить его. По возвращении отсрочки выполняются в обратном порядке, поэтому мы знаем, что сбрасываем в правильном порядке, потому что отсрочки для уничтожения находятся рядом с вызовами функции для создания.