Как я могу улучшиться/заменить sprintf, который я измерил, чтобы быть горячей точкой производительности?

<Route path="/blog/:id" component={BlogSingle} />

Для этого маршрута, потому что меняется только один из параметров, а маршрут остается тем же, что ваш компонент останется подключенным. Если в BlogSingle у вас есть логика для определения того, что отображается с помощью componentDidMount, вам нужно поместить эту логику в componentDidUpdate и правильно обновить компонент, когда ваши параметры меняются в пропозиции match, которую проходит маршрут.

8
задан John Carter 18 February 2009 в 12:13
поделиться

11 ответов

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

править: Обратите внимание что справиться с секундами прыжка (и соответствовать strftime()) необходимо смочь распечатать значения секунд 60 и 61.

char LeadingZeroIntegerValues[62][] = { "00", "01", "02", ... "59", "60", "61" };

С другой стороны, как насчет strftime()? Я понятия не имею, как производительность выдерживает сравнение (она могла просто называть sprintf ()), но это стоит посмотреть на (и она могла делать сам вышеупомянутый поиск).

18
ответ дан 5 December 2019 в 04:43
поделиться

Трудно предположить, что Вы собираетесь победить sprintf при форматировании целых чисел. Вы - верный sprintf, Ваша проблема?

0
ответ дан 5 December 2019 в 04:43
поделиться

StringStream является предположением, что я добрался от Google.

http://bytes.com/forum/thread132583.html

0
ответ дан 5 December 2019 в 04:43
поделиться

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

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

1
ответ дан 5 December 2019 в 04:43
поделиться

Я сделал бы несколько вещей...

  • кэшируйте текущее время, таким образом, Вы не должны повторно создавать метку времени каждый раз
  • сделайте преобразование времени вручную. Самая медленная часть printf- функции семейства являются парсингом строки формата, и глупо посвятить циклы тому парсингу на каждом выполнении цикла.
  • попытайтесь использовать 2-байтовые справочные таблицы для всех преобразований ({ "00", "01", "02", ..., "99" }). Это вызвано тем, что Вы хотите избежать moduluar арифметики, и 2-байтовая таблица означает, что только необходимо использовать один модуль, в течение года.
2
ответ дан 5 December 2019 в 04:43
поделиться

Похож на Разиню, предлагает, очень похожий метод (победите меня меньше чем на час).

В дополнение к уже предложенному методу справочной таблицы (n2s [] выстраивают ниже), как насчет того, чтобы генерировать Ваш буфер формата так, чтобы обычный sprintf был менее интенсивным? Код ниже должен будет только заполнить минуту и второй каждый раз через цикл, если год/месяц/день/час не изменился. Очевидно, если какой-либо из тех изменился, Вы действительно получаете другой sprintf удар, но в целом это не могут быть больше, чем, что Вы в настоящее время свидетельствуете (в сочетании с поиском массива).


static char fbuf[80];
static SYSTEMTIME lastSysTime = {0, ..., 0};  // initialize to all zeros.

for (int i = 0; i < 100000; i++)
{
    if ((lastSysTime.wHour != sysTime.wHour)
    ||  (lastSysTime.wDay != sysTime.wDay)
    ||  (lastSysTime.wMonth != sysTime.wMonth)
    ||  (lastSysTime.wYear != sysTime.wYear))
    {
        sprintf(fbuf, "%4d-%02s-%02s %02s:%%02s:%%02s",
                sysTime.wYear, n2s[sysTime.wMonth],
                n2s[sysTime.wDay], n2s[sysTime.wHour]);

        lastSysTime.wHour = sysTime.wHour;
        lastSysTime.wDay = sysTime.wDay;
        lastSysTime.wMonth = sysTime.wMonth;
        lastSysTime.wYear = sysTime.wYear;
    }

    sprintf(buf, fbuf, n2s[sysTime.wMinute], n2s[sysTime.wSecond]);

}
3
ответ дан 5 December 2019 в 04:43
поделиться

Printf должен иметь дело с большим количеством различных форматов. Вы, конечно, могли захватить источник для printf и использовать его в качестве основания к версии самокрутки, которая имеет дело конкретно с sysTime структурой. Тем путем Вы передаете в одном аргументе, и он делает просто точно работу, которая должна быть сделана и ничто больше.

6
ответ дан 5 December 2019 в 04:43
поделиться

Вы могли попытаться заполнить каждый символ в выводе в свою очередь.

buf[0] = (sysTime.wYear / 1000) % 10 + '0' ;
buf[1] = (sysTime.wYear / 100) % 10 + '0';
buf[2] = (sysTime.wYear / 10) % 10 + '0';
buf[3] = sysTime.wYear % 10 + '0';
buf[4] = '-';

... и т.д...

Не симпатичный, но Вы получаете изображение. Если ничто иное, это может помочь объяснить, почему sprintf не будет этим быстро.

OTOH, возможно, Вы могли кэшировать последний результат. Тем путем необходимо было бы только генерировать тот каждую секунду.

6
ответ дан 5 December 2019 в 04:43
поделиться

Как насчет того, чтобы кэшировать результаты? Разве это не возможность? Полагая, что этот конкретный sprintf () вызов делается слишком часто в Вашем коде, я предполагаю, что между большинством этих последующих вызовов, год, месяц и день не изменяются.

Таким образом мы можем реализовать что-то как следующее. Объявите старое и текущую структуру СИСТЕМНОГО ВРЕМЕНИ:

SYSTEMTIME sysTime, oldSysTime;

Кроме того, объявите, что отдельные части содержат дату и время:

char datePart[80];
char timePart[80];

Поскольку, в первый раз необходимо будет заполнить и sysTime, oldSysTime, а также datePart и timePart. Но последующий sprintf () может быть сделан вполне быстрее, как дали ниже:

sprintf (timePart, "%02d:%02d:%02d", sysTime.wHour, sysTime.wMinute, sysTime.wSecond);
if (oldSysTime.wYear == sysTime.wYear && 
  oldSysTime.wMonth == sysTime.wMonth &&
  oldSysTime.wDay == sysTime.wDay) 
  {
     // we can reuse the date part
     strcpy (buff, datePart);
     strcat (buff, timePart);
  }
else {
     // we need to regenerate the date part as well
     sprintf (datePart, "%4d-%02d-%02d", sysTime.wYear, sysTime.wMonth, sysTime.wDay);
     strcpy (buff, datePart);
     strcat (buff, timePart);
}

memcpy (&oldSysTime, &sysTime, sizeof (SYSTEMTIME));

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

2
ответ дан 5 December 2019 в 04:43
поделиться

Что Вы подразумеваете под "долгим" временем - начиная с sprintf() единственный оператор в Вашем цикле, и "инфраструктура" цикла (инкремент, сравнение) незначительна, sprintf() должен использовать большую часть времени.

Помните старую шутку о человеке, который потерял его обручальное кольцо на 3-й улице однажды ночью, но искал ее на 5-м, потому что свет был более ярким там? Вы создали пример, это разработано для "доказывания" предположения это sprintf() неэффективно.

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

Вы можете быть удивлены результатами.

3
ответ дан 5 December 2019 в 04:43
поделиться

В данный момент я работаю над аналогичной проблемой.

Мне нужно регистрировать операторы отладки с меткой времени, именем файла, номером строки и т. Д. Во встроенной системе. У нас уже есть регистратор, но когда я поворачиваю ручку в «полное ведение журнала», он съедает все наши циклы обработки и переводит нашу систему в ужасное состояние, заявляя, что ни одно вычислительное устройство никогда не должно испытывать это.

Кто-то сказал «Вы не можете измерить / наблюдать что-то, не изменяя то, что вы измеряете / наблюдаете».

Поэтому я меняю вещи, чтобы улучшить производительность. Текущее положение вещей таково, что Im в 2 раза быстрее, чем исходный вызов функции (узкое место в этой системе журналирования не в вызове функции, а в средстве чтения журнала, которое является отдельным исполняемым файлом, который я могу отбросить, если Я пишу свой собственный стек журналирования).

Интерфейс, который мне нужно предоставить, похож на - void log (int channel, char * filename, int lineno, format, ...) . Мне нужно добавить имя канала (который в настоящее время выполняет линейный поиск в списке! Для каждого отдельного оператора отладки!) И метку времени, включая счетчик миллисекунд. Вот некоторые вещи, которые я делаю, чтобы сделать это более быстрым -

  • Stringify название канала, чтобы я мог strcpy вместо того, чтобы искать в списке. определить макрос LOG (канал, ... и т. д.) как log (#channel, ... и т. д.) . Вы можете использовать memcpy , если вы фиксируете длину строки, определяя LOG (channel, ...) log ("...." # channel - sizeof (".. ..» #channel) + * 11 *) , чтобы получить фиксированные 10 длины каналов байтов
  • Генерировать строку метки времени пару раз в секунду. Вы можете использовать asctime или что-то. Затем memcpy строка фиксированной длины для каждого оператора отладки.
  • Если вы хотите сгенерировать строку метки времени в реальном времени, тогда справочная таблица с присваиванием (не memcpy!) Идеальна. Но это работает только для двузначных чисел и, возможно, для года.
  • Как насчет трехзначных (миллисекунд) и пятизначных (белья)? Мне не нравится itoa, и мне не нравятся пользовательские itoa ( digit = ((value / = value)% 10) ), потому что div и моды медленны . Я написал нижеприведенные функции, а потом обнаружил, что нечто подобное есть в руководстве по оптимизации AMD (в сборке), которое дает мне уверенность в том, что это самые быстрые реализации языка Си. { * string ++ = '0' + ((значение = значение * 2684355) >> 28); * string ++ = '0' + ((value = ((value & 0x0FFFFFFF)) * 10) >> 28); * string ++ = '0' + ((value = ((value & 0x0FFFFFFF)) * 10) >> 28); * string ++ = ''; / * null заканчивается здесь, если это то, что вам нужно * / }

    Аналогично, для номеров строк,

     void itoa05 (char * string, unsigned int value)
    {
     * string ++ = '';
     * string ++ = '0' + ((значение = значение * 26844 + 12) >> 28);
     * string ++ = '0' + ((value = ((value & 0x0FFFFFFF)) * 10) >> 28);
     * string ++ = '0' + ((value = ((value & 0x0FFFFFFF)) * 10) >> 28);
     * string ++ = '0' + ((value = ((value & 0x0FFFFFFF)) * 10) >> 28);
     * string ++ = '0' + ((value = ((value & 0x0FFFFFFF)) * 10) >> 28);
     * string ++ = ''; / * null заканчивается здесь, если это то, что вам нужно * /
    }
    

В целом, мой код довольно быстр. vsnprintf () , который мне нужно использовать, занимает около 91% времени, а остальная часть моего кода занимает только 9% (тогда как остальная часть кода, т. Е. За исключением vsprintf () используется занять 54% раньше)

1
ответ дан 5 December 2019 в 04:43
поделиться