C/C++ лучший способ отправить несколько байтов на стандартный вывод
-
22-08-2019 - |
Вопрос
Профилирование моей программы и функция печати занимают много времени.Как я могу отправить «необработанный» байтовый вывод непосредственно на стандартный вывод вместо использования fwrite и сделать его быстрее (необходимо одновременно отправить все 9 байтов в print() на стандартный вывод)?
void print(){
unsigned char temp[9];
temp[0] = matrix[0][0];
temp[1] = matrix[0][1];
temp[2] = matrix[0][2];
temp[3] = matrix[1][0];
temp[4] = matrix[1][1];
temp[5] = matrix[1][2];
temp[6] = matrix[2][0];
temp[7] = matrix[2][1];
temp[8] = matrix[2][2];
fwrite(temp,1,9,stdout);
}
Матрица определяется глобально как беззнаковая символьная матрица[3][3];
Решение
IO — недешевая операция.Фактически это блокировка это означает, что ОС может вытеснить ваш процесс, когда вы вызываете write
чтобы разрешить запуск большего количества процессов, связанных с ЦП, до того, как устройство ввода-вывода, на которое вы записываете, завершит операцию.
Единственная функция более низкого уровня, которую вы можете использовать (если вы разрабатываете на машине *nix), — это использовать необработанный файл write
функция, но даже тогда ваша производительность не будет намного быстрее, чем сейчас.Проще говоря:ИО стоит дорого.
Другие советы
Ответ с самым высоким рейтингом утверждает, что ввод-вывод работает медленно.
Вот быстрый тест с достаточно большим буфером, чтобы вывести ОС из критического пути производительности, но только если вы готовы получать результаты в виде гигантских пятен.Если ваша проблема заключается в задержке первого байта, вам нужно работать в режиме «дробов».
Запишите 10 миллионов записей из девятибайтового массива.
Mint 12 AMD64 на процессоре CoreDuo 3 ГГц под gcc 4.6.1
340ms to /dev/null
710ms to 90MB output file
15254ms to 90MB output file in "dribs" mode
FreeBSD 9 AMD64 на процессоре CoreDuo 2,4 ГГц под clang 3.0
450ms to /dev/null
550ms to 90MB output file on ZFS triple mirror
1150ms to 90MB output file on FFS system drive
22154ms to 90MB output file in "dribs" mode
В вводе-выводе нет ничего медленного, если вы можете позволить себе правильно буферизоваться.
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char* argv[])
{
int dribs = argc > 1 && 0==strcmp (argv[1], "dribs");
int err;
int i;
enum { BigBuf = 4*1024*1024 };
char* outbuf = malloc (BigBuf);
assert (outbuf != NULL);
err = setvbuf (stdout, outbuf, _IOFBF, BigBuf); // full line buffering
assert (err == 0);
enum { ArraySize = 9 };
char temp[ArraySize];
enum { Count = 10*1000*1000 };
for (i = 0; i < Count; ++i) {
fwrite (temp, 1, ArraySize, stdout);
if (dribs) fflush (stdout);
}
fflush (stdout); // seems to be needed after setting own buffer
fclose (stdout);
if (outbuf) { free (outbuf); outbuf = NULL; }
}
Самая необработанная форма вывода, которую вы можете сделать, — это вероятное write
системный вызов, вот так
write (1, matrix, 9);
1 — файловый дескриптор стандартного вывода (0 — стандартный ввод, 2 — стандартная ошибка).Ваш стандартный выход будет писать так же быстро, как и тот, кто читает его на другом конце (т.терминал или программу, в которую вы передаете данные), что может быть довольно медленным.
Я не уверен на 100%, но вы можете попробовать настроить неблокирующий ввод-вывод на диске 1 (используя fcntl
) и надейтесь, что ОС будет буферизовать его до тех пор, пока он не будет использован другим концом.Прошло много времени, но я думаю, что это работает вот так
fcntl (1, F_SETFL, O_NONBLOCK);
YMMV, однако.Пожалуйста, поправьте меня, если я ошибаюсь в синтаксисе, как я уже сказал, прошло много времени.
Возможно, ваша проблема не в том, что fwrite() работает медленно, а в том, что она буферизуется.Попробуйте вызвать fflush(stdout) после fwrite().
Все это действительно зависит от вашего определения медленного в этом контексте.
Вся печать происходит довольно медленно, хотя iostreams действительно медленны для печати.
Лучше всего было бы использовать printf, что-то вроде:
printf("%c%c%c%c%c%c%c%c%c\n", matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0],
matrix[1][1], matrix[1][2], matrix[2][0], matrix[2][1], matrix[2][2]);
Вы можете просто:
std::cout << temp;
печать это больше C-стиль.
Однако операции ввода-вывода являются дорогостоящими, поэтому используйте их с умом.
Как все уже отмечали, ввод-вывод в тесном внутреннем цикле обходится дорого.Обычно я выполнял условный расчет Matrix на основе некоторых критериев, когда это требовалось для ее отладки.
Если ваше приложение является консольным, попробуйте перенаправить его в файл, это будет намного быстрее, чем обновление консоли.например app.exe > matrixDump.txt
Что случилось с:
fwrite(matrix,1,9,stdout);
и одномерный, и двумерный массивы занимают одну и ту же память.
Попробуйте запустить программу дважды.Один раз с выходом и один раз без.Вы заметите, что в целом тот, у кого нет io, самый быстрый.Кроме того, вы можете разветвить процесс (или создать поток), один записывает в файл (stdout), а другой выполняет операции.