Почему snprintf быстрее ostringstream или нет?

Я где-то читал, что snprintf быстрее, чем ostringstream. У кого-нибудь есть опыт с этим? Если да, то почему это быстрее.


person kal    schedule 15.01.2009    source источник


Ответы (9)


std::ostringstream не требуется, чтобы он был медленнее, но, как правило, он работает медленнее. На веб-сайте FastFormat есть несколько тестов.

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

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

person Max Lybbert    schedule 15.01.2009
comment
Вау - я уже давно не был на сайте Мэтью Уилсона - похоже, он был занят последние несколько месяцев ... - person Michael Burr; 15.01.2009
comment
Тесты FastFormat необъективны. Загрузив код, вы увидите, что тесты snprintf () вызывают функцию с именем fastformat_util_snprintf (), которая включает некоторый код оболочки, который, вероятно, сбрасывает тесты. Но вы правы, вероятно, именно управление памятью замедляет работу ostringstream. - person Max; 16.01.2009
comment
Спасибо, что посмотрели код. Я только посмотрел на красивые графики. - person Max Lybbert; 20.01.2009
comment
Макс, ты не прав относительно тестов snprintf (). Проверьте код еще раз - person dcw; 16.03.2009
comment
Я не проводил тесты, и я не могу обновить веб-сайт Мэтта Уилсона или его код. Я придерживаюсь исходного утверждения (что они не предназначены для работы медленнее, но обычно реализуются медленнее). Если вам не нравятся тесты Мэтта Уилсона, я уверен, что немного погуглите, и вы найдете другие. - person Max Lybbert; 17.03.2009
comment
Между прочим, Мэтт Уилсон написал библиотеки STLSoft, так что я готов согласиться с его тестами только по имени. - person Max Lybbert; 17.03.2009
comment
Думаю, dcw имел в виду другой Макс. :) В любом случае FastFormat выглядит неплохо, а библиотека std IOStreams безнадежно испорчена. Но из-за запутанной установки библиотеки для меня это немного не запускается. Если мне придется возиться с переменными env, я найду другую библиотеку. - person jalf; 12.12.2009
comment
РЖУ НЕ МОГУ. Спасибо, jalf. Я забыл об этом вопросе; и перечитывая думаю ты прав. - person Max Lybbert; 15.12.2009
comment
Одна из причин заключается в том, что строковые потоки обычно являются потокобезопасными, а snprintf - нет, поэтому здесь есть некоторые накладные расходы. - person Johan Kotlinski; 12.08.2010
comment
Семейство функций printf поддерживает локали, как и iostream. @kotlinski: Они также безопасны для потоков. - person ; 09.07.2012
comment
Спасибо, @JoeWreschnig. Я обновил ответ после прочтения книги Standard C ++ Iostreams and Locales: Advanced Programmer's Guide and Reference, в которой рассказывается о том, что IOStreams должен делать для поддержки локалей, но не о том, что уже сделали snprintf и другие функции. Я удалил ссылку на локали. - person Max Lybbert; 10.07.2012

Мы заменили некоторые строковые потоки во внутренних циклах на sprintf (с использованием статически распределенных буферов), и это имело большое значение как в msvc, так и в gcc. Я предполагаю, что управление динамической памятью этого кода:

{
  char buf[100];
  int i = 100;
  sprintf(buf, "%d", i);
  // do something with buf
}

намного проще, чем

{
  std::stringstream ss;
  int i = 100;
  ss << i;
  std::string s = ss.str();
  // do something with s
}

но я очень доволен общей производительностью струнных потоков.

person user52875    schedule 15.01.2009

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

Вы вряд ли когда-нибудь заметите разницу, кроме тестов. Причина того, что потоки C ++ обычно имеют тенденцию быть медленнее, заключается в том, что они гораздо более гибкие. Гибкость чаще всего достигается либо за счет времени, либо за счет роста кода.

В этом случае потоки C ++ основаны на потоковых буферах. Сами по себе потоки - это всего лишь оболочка, которая хранит флаги форматирования и ошибок на месте и вызывает правильные i/o фасеты стандартной библиотеки c ++ (например, num_put для печати чисел), которые печатают значения, хорошо отформатированные, в базовый поток. -буфер, подключенный к потоку c ++.

Все эти механизмы - фасеты и буферы - реализуются виртуальными функциями. Хотя на самом деле нет отметки примечание, эти функции должны быть реализованы медленнее, чем c stdio pendants, этот факт сделает их несколько медленнее, чем использование функций c stdio в обычном режиме (я тестировал это некоторое время назад с gcc / libstdc ++ и на самом деле заметил замедление, но которое вы почти не замечаете при повседневном использовании).

person Johannes Schaub - litb    schedule 15.01.2009

Абсолютно это зависит от реализации.

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

Тогда ты бы знал.

person Paul Beckingham    schedule 15.01.2009

Одна из проблем, вероятно, будет заключаться в том, что безопасность типов, добавленная ostringstream, несет дополнительные накладные расходы. Однако я не проводил никаких измерений.

person Johann Gerell    schedule 15.01.2009

Как сказано в litb, стандартные потоки поддерживают многие вещи, которые нам не всегда нужны. Некоторые реализации потоков избавляются от этой никогда не использовавшейся гибкости, например, см. FAStream.

person Luc Hermitte    schedule 15.01.2009
comment
Что случилось с FAStream? Я видел некоторые ответы на форуме, использующие их, но теперь я не могу найти никакой информации об этом. - person Javi; 30.04.2014
comment
Увы, не знаю. Думаю, лучше всего спросить напрямую у автора. - person Luc Hermitte; 30.04.2014
comment
Ссылка теперь мертва - person Eric; 23.03.2018

Вполне возможно, потому что sprintf является частью CRT, написанной на ассемблере. ostringstream является частью STL и, вероятно, написан немного более обобщенно, и имеет код ООП / накладные расходы, с которыми нужно работать.

person LarryF    schedule 15.01.2009
comment
Я очень сильно сомневаюсь, что кто-нибудь когда-либо реализовал sprintf на ассемблере, кроме, возможно, упражнения в мазохизме. Начиная с UNIX V6, сама библиотека времени выполнения C была написана на C (за исключением крошечной горстки вещей, которые невозможно написать на C, например setjmp). - person zwol; 19.09.2012

Да, если вы запустите приведенную ниже функцию для нескольких миллионов чисел с помощью Visual C ++ 5.0, первая версия займет примерно вдвое больше времени, чем вторая, и выдаст тот же результат.

Компиляция жестких циклов в .exe и запуск Windows timethis something.exe' or the Linuxtime something »- вот как я исследую большинство своих любопытных вопросов, связанных с производительностью. ("timethis" где-нибудь в сети)

void Hex32Bit(unsigned int n, string &result)
{
#if 0
    stringstream ss;
    ss
        << hex
        << setfill('0')
        << "0x" << setw(8) << n
    ;
    result = ss.str();
#else
    const size_t len = 11;
    char temp[len];
    _snprintf(temp, len, "0x%08x", n);
    temp[len - 1] = '\0';
    result = temp;
#endif
}
person Matthew    schedule 12.12.2009
comment
Вы компилируете с оптимизацией? Если нет, то ваши результаты не интересны - а если да, то компилятор, скорее всего, оптимизируется до void Hexx32Bit(...) {} - person Eric; 23.03.2018

Одна из причин, по которой я знаю, что семейство функций printf быстрее, чем соответствующие функции C ++ (cout, cin и другие потоки), заключается в том, что последние выполняют проверку типов. Поскольку это обычно связано с некоторыми запросами к перегруженным операторам, это может занять некоторое время.

Фактически, на соревнованиях по программированию часто рекомендуется использовать printf et al, а не cout / cin именно по этой причине.

person sykora    schedule 15.01.2009
comment
Этот вид проверки типов, а также перегрузка операторов устраняются во время компиляции. Снижение производительности во время выполнения ими не объясняется. - person Pyry Jahkola; 15.01.2009
comment
Фактически, семейство printf () должно анализировать формат во время выполнения, что не соответствует наблюдению. - person MSalters; 15.01.2009
comment
Проверка типов C ++ - это не затраты времени выполнения. Если вы не говорите о скорости компиляции, в этом случае <iostream> ужасен. - person Tom; 12.12.2009