QString::number(int)
много раз в секунду. Это очень медленно: кажется, что каждый раз выделяется новая строка. Пытался использовать setNum
вместо этого на одной струне все еще нет радости.Оригинальный, длинный вопрос:
У меня есть большой массив чисел (скажем, целых чисел), и я хочу отформатировать их в текст, который затем (возможно, не сразу) будет записан в файл. Наивный способ выглядит примерно1 как это:
QString allData;
foreach(const int & value, values) {
allData += QString::number(value);
allData += '\n';
}
Это занимает около 280ms за 150000 целые числа на моей машине, что мне кажется очень много. Я полагаю, что это потому, что QString::number
вызывается 150000 раз и каждый раз выделяет новую строку. Это каким-то образом подтверждается, что корень проблемы, когда я пытаюсь использовать itoa
(который не выделяет память) вместо этого.
[not-cute]
решениеQString allData;
char buffer[100]; // <-------
foreach(const int & value, values) {
_itoa_s(value, buffer, sizeof(buffer), 10); // <-------
allData += buffer;
allData += '\n';
}
Это занимает около 70ms для того же 150000 целые числа (о 4x быстрее), что сейчас приемлемо для меня (Я думаю, что я могу сделать что-то и с конкатенацией строк, но давайте оставим это вне этого вопроса)
Но Мне не нравится, что я должен использовать некоторые нестандартные, вероятно, устаревшие, вероятно, не переносимые2 функция (не сказать, что это выглядит просто уродливо).
Тогда я вспомнил, что есть также пример метод: QString::setNum
. Я надеялся, что смогу использовать тот же шаблон, что и с itoa
: выделите только одну строку и изменяйте ее каждый раз.
QString allData;
QString number; // <-------
foreach(const int & value, values) {
number.setNum(value); // <-------
allData += number;
allData += '\n';
}
К сожалению, это не имеет большого значения от QString::number
: опять около 280мс, ну может быть 250мс но все равно слишком много.
Итак, поздравляю, если вы достигли здесь 🙂 и, наконец, …
itoa
несмотря на отчетливый запах C в другом ароматном C ++ / Qt-коде?setNum
не сделал трюк?Примечания:
1 В реальном коде у меня есть не только 150000 целых чисел, но 50000 троек целых чисел, которые я также добавляю '\t'
между ними. Это единственное отличие от моего реального кода, и я думаю, что это не важно: здесь меня интересует только производительность QString::number
против itoa
,
2 На самом деле, я был удивлен, что MinGW также имеет _itoa_s
он ведет себя так же, как и Visual Studio, но у меня все еще есть какое-то неловкое ощущение, что использование такой грязной функции в моем отшлифованном коде Qt уменьшает его переносимость. Поправьте меня если я ошибаюсь.
Вы можете попробовать использовать 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