Как мне добавить буферизацию для 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, что все готово, чтобы он мог записать свои внутренние буферы, которые он сохранял для следующей пакетной записи. Наконец, нам нужно сообщить ОС, что мы закончили с файлом.

Это разрушение происходит в порядке, обратном созданию, поэтому мы можем использовать отсрочку, чтобы упростить его. По возвращении отсрочки выполняются в обратном порядке, поэтому мы знаем, что сбрасываем в правильном порядке, потому что отсрочки для уничтожения находятся рядом с вызовами функции для создания.

Другие вопросы по тегам