Правильный способ преобразования (много!) чисел в строки без выделения в Qt
tl; dr
Я хочу позвонить QString::number(int)
много раз в секунду. Это очень медленно: кажется, что он выделяет новую строку каждый раз. Пытался использовать setNum
на той же строке вместо этого, по-прежнему нет радости.
оригинальный, длинный вопрос:
проблема
у меня есть большой массив чисел (скажем, целых чисел), и я хочу отформатировать их в текст, который будет затем (возможно, не сразу) записан в файл. Наивно выглядит примерно в1 такой:
QString allData;
foreach(const int & value, values) {
allData += QString::number(value);
allData += 'n';
}
это займет около 280ms на 150000 целыми на моей машине, которая, кажется, много для меня. Я полагаю, это потому, что QString::number
вызывается 150000 раз и каждый раз выделяет новую строку. Это каким-то образом подтверждено, что корень проблемы, когда я пытаюсь использовать itoa
(который не выделяет память) вместо этого.
возможно, но не на Qt [not-cute]
решение
QString allData;
char buffer[100]; // <-------
foreach(const int & value, values) {
_itoa_s(value, buffer, sizeof(buffer), 10); // <-------
allData += buffer;
allData += 'n';
}
это займет около 70мс в той же 150000 целые числа (около 4х быстрее), что теперь приемлемо для меня (я думаю, что могу сделать что-то с конкатенацией строк, но давайте оставим это за пределами этого вопроса)
но мне не нравится, что я должен использовать какой-то нестандартный, вероятно, устаревший, вероятно, непортящийся2 (не сказать, что это просто выглядит некрасиво).
тогда я вспомнил, что есть еще экземпляр способ: QString::setNum
. Я надеялся, что смогу использовать тот же шаблон, что и с itoa
: выделите только одну строку и измените ее каждый раз.
желательно, но не работает решение
QString allData;
QString number; // <-------
foreach(const int & value, values) {
number.setNum(value); // <-------
allData += number;
allData += 'n';
}
к сожалению, это не имеет большого значения от QString::number
: снова о 280ms, ну, может быть 250мс но все-таки слишком много.
Итак, поздравляю, если вы достигли здесь :) и, наконец...
вопрос(ы)
-
что посоветовали бы мне эксперты Qt сделать? Заткнись и используй
itoa
несмотря на отчетливый запах C в противном случае ароматный код C++ / Qt? - или я могу как-то сказать "давай, Qstring, просто съешь это число в себя" ?
- интересно почему
setNum
не делать трик!--34-->?
Примечания:
1 в фактическом коде у меня есть не только 150000 целых чисел, но и 50000 тройки целых чисел, которые я также добавляю
't'
между ними. Это единственное отличие от моего фактического кода, и я думаю, это не важно: здесь меня интересует только производительностьQString::number
vsitoa
.2 на самом деле, я был удивлен, что MinGW также имеет
_itoa_s
это ведет себя так же, как визуальный Studio, но у меня все еще есть неловкое чувство, что использование такой грязной функции в моем полированном коде Qt уменьшает его переносимость. Поправьте меня, если я ошибаюсь.
2 ответов
вы можете попробовать с QByteArray, который разделяет тот же интерфейс QString, но более подходит для проблем с производительностью.Я получаю 36 МС (Qt 5.2 clang) против ваших исходных 57 МС (на моей машине) с этим кодом:
QByteArray allDatab;
foreach(const int & value, values) {
allDatab += QByteArray::number(value);
allDatab += '\n';
}
QString result(allDatab);
и 29 МС с этой версией (что, возможно, подтверждает ваши предположения о setNum):
QByteArray allDatad;
QByteArray number;
foreach(const int & value, values) {
number.setNum(value);
allDatad += number;
allDatad += '\n';
}
как насчет использования STL?
Я проверил ваш код (изменение цикла для упрощения)
int main() {
stringstream ss;
for(int i=0; i<2000000; ++i) {
ss << i << "\n";
}
}
и я
time ./ss_test
real 0m0.146s
user 0m0.139s
sys 0m0.006s
С версией Qt (в моей машине)
int main() {
QString allData;
for(int i=0; i<2000000; ++i) {
allData += QString::number(i);
allData += '\n';
}
}
получить
time ./qtstring_test
real 0m0.516s
user 0m0.508s
sys 0m0.008s