Почему snprintf быстрее, чем ostringstream? - PullRequest
22 голосов
/ 15 января 2009

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

Ответы [ 9 ]

25 голосов
/ 15 января 2009

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

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

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

9 голосов
/ 15 января 2009

Мы заменили некоторые строковые потоки во внутренних циклах на 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
}

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

8 голосов
/ 15 января 2009

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

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

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

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

3 голосов
/ 15 января 2009

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

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

Тогда вы бы знали.

1 голос
/ 15 января 2009

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

0 голосов
/ 12 декабря 2009

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

Компиляция жестких циклов в .exe и запуск Windows timethis something.exe' or the Linux раз что-то '- это то, как я исследую большую часть своего любопытства по поводу производительности. («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
}
0 голосов
/ 15 января 2009

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

0 голосов
/ 15 января 2009

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

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

0 голосов
/ 15 января 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...