Найти тему
2015 подписчиков

👣 Существует ли аналог std::endl и std::flush в Go?


⏩Итак, мы все знаем, что в большинстве пользовательских современных ОС стандартный ввод и вывод работает через буфер. Чтобы буфер скинуть в C++ есть std::flush и std::endl, который ещё и переносит на новую строку. Есть ли такое в Go?

⏩Если коротко, то нет, не существует.

Практически все операции вывода в Go используют интерфейсы io.Writer или io.WriteCloser. В этих интерфейсах есть только метод Write. Эти интерфейсы радикально проще стандартного std::basic_stream. Метод Flush или аналоги в io.Writer отсутствуют.

Теперь об объектах std::cin и std::cout. В Go им соответствуют os.Stdin и os.Stdout. Переменная os.Stdout — это указатель на объект типа os.File.

В Go вывод в файлы не буферизуется, метод File.Write пишет напрямую в файловый дескриптор через системный вызов pwrite. Соответственно, в типе File нет метода, аналогичного std::Flush. Есть метод Sync, который вызывает системный вызов fsync для открытого файлового дескриптора, но это не то. Этот системный вызов заставляет ядро сбросить на диск буферы, отведённые под файловый дескриптор.

Из-за того, что File пишет напрямую в файл, функции fmt.Print и fmt.Println, а так же методы File.WriteString и File.Write, очень медленные. На больших объемах вывода они медленнее буферизованного вывода раз в 100.

Буферизованный ввод-вывод предоставляет пакет bufio. В пакете определён тип bufio.Writer, в котором есть метод Flush. Этот тип в десятки раз ускоряет вывод, но, к сожалению, нет типа для буферизованного файла: нельзя написать os.Stdout = bufio.NewWriter(os.Stdout). Поэтому если вам нужен быстрый аналог fmt.Print, то нужно пользоваться fmt.Fprint и явно указывать writer:
Stdout_Buffered := bufio.NewWriter(os.Stdout)
...
fmt.Fprintln(Stdout_Buffered, "Hello, world!")
...
Stdout_Buffered.Flush()
Аналога для std::endl в стандартных пакетах Go нет.

Функция fmt.Fprintln пишет в объект io.Writer системно-зависимый конец строки, но, поскольку io.Writer не содержит никаких аналогов flush, нижележащий буфер (если есть) эта функция не синхронизует.

1 минута