Производительность ввода C ++ - PullRequest
7 голосов
/ 01 февраля 2012

Я пытался решить проблему на InterviewStreet.Через некоторое время я определяю, что на самом деле трачу большую часть своего времени на чтение входных данных.Этот конкретный вопрос имел большой вклад, так что это имеет смысл.Что не имеет смысла, так это то, почему различные методы ввода имели такие разные характеристики:

Первоначально у меня было:

std::string command;
std::cin >> command;

Замена этого сделала его заметно быстрее:

char command[5];
cin.ignore();
cin.read(command, 5);

Перезапись всего, чтобы использовать scanf, сделала его еще быстрее

char command;
scanf("get_%c", &command);

Все сказали, что я сократил время чтения ввода примерно на 1/3.

Мне интересно, есть литакое изменение в производительности между этими различными методами.Кроме того, мне интересно, почему использование gprof не выдвинуло на первый план то время, которое я тратил на ввод-вывод, а скорее показало, что виноват мой алгоритм.

Ответы [ 4 ]

2 голосов
/ 01 февраля 2012

В этих подпрограммах есть большой разброс, поскольку скорость ввода с консоли почти никогда не имеет значения.

И там, где это происходит (оболочка Unix), код написан на C, читает напрямую с устройства stdin и работает эффективно.

1 голос
/ 02 февраля 2012

gprof сэмплирует только во время процессора, а не во время блокировки. Таким образом, программа может тратить час на выполнение операций ввода-вывода, а микросекунды - на вычисления, и gprof будет видеть только микросекунды .

По какой-то причине это не очень хорошо известно.

1 голос
/ 01 февраля 2012

При риске понижения, потоки ввода / вывода, как правило, медленнее и объемнее, чем их аналоги на языке Си. Это не причина избегать их использования, хотя во многих целях они более безопасны (когда-либо сталкивались с ошибкой scanf или printf? Не очень приятно) и более общие (например: перегруженный оператор вставки, позволяющий выводить пользовательские типы). Но я бы также сказал, что это не повод использовать их догматически в очень критичном для кода исполнении.

Хотя я нахожу результаты немного удивительными. Из трех перечисленных вами я бы заподозрил, что это будет быстрее всего:

char command[5];
cin.ignore();
cin.read(command, 5);

Причина: не требуется выделения памяти и прямое чтение символьного буфера. Это также верно для вашего примера C ниже, но вызов scanf для многократного чтения одного символа также далеко не оптимален даже на концептуальном уровне, так как scanf должен анализировать строку формата, которую вы передали каждый раз. Я был бы заинтересован в деталях вашего кода ввода / вывода, поскольку кажется, что есть вероятность, что что-то не так произойдет, когда вызовы scanf для чтения одного символа окажутся самыми быстрыми. Я просто должен спросить и не хочу обидеть, но действительно ли код скомпилирован и связан с оптимизацией?

Теперь что касается вашего первого примера:

std::string command;
std::cin >> command;

Мы можем ожидать, что это будет немного медленнее, чем оптимальное, по причине того, что вы работаете с контейнером переменного размера (std :: string), который должен будет включать некоторые выделения кучи для чтения в желаемом буфере. Когда дело доходит до проблем стека и кучи, стек всегда значительно быстрее, поэтому, если вы можете предвидеть максимальный размер буфера, необходимый в конкретном случае, простой символьный буфер в стеке превзойдет std :: string для ввода (даже если Вы использовали резерв). Это также верно для массива в стеке, в отличие от std :: vector, но эти контейнеры лучше всего использовать в тех случаях, когда вы не можете заранее предвидеть размер. Где std :: string может быть быстрее, могут быть случаи, когда у людей может возникнуть желание повторно вызывать strlen, когда лучше хранить и поддерживать переменную размера.

Что касается деталей gprof, они должны освещать эти проблемы. Вы смотрите на полный график звонков, а не на плоский профиль? Естественно, плоский профиль может вводить в заблуждение в этом случае. Мне нужно знать некоторые подробности о том, как вы используете gprof, чтобы дать лучший ответ.

0 голосов
/ 12 июня 2016

По умолчанию стандартные iostreams настроены для совместной работы и с библиотекой C stdio - на практике это означает, что cin и cout для вещей, отличных от интерактивного ввода и вывода, имеют тенденцию быть медленными.

Чтобы получить хорошую производительность при использовании cin и cout, вам нужно отключить синхронизацию с stdio.Для высокопроизводительного ввода вы, возможно, даже захотите развязать потоки.

Подробнее см. Следующий вопрос stackoverflow.

Как заставить IOStream работать лучше?

...