So, hier mal ein Minimalbeispiel mit Zeitmessung und Ausgabe
Code: Alles auswählen
#include <cstdlib>
#include <ctime>
#include <QtCore/QFile>
#include <QtCore/QList>
#include <QtCore/QTime>
int main(int argc, char *argv[]) {
srand(time(NULL));
QFile file("testfile.txt");
// create
qDebug("Creating testfile...");
file.open(QIODevice::WriteOnly | QIODevice::Text);
for (int i=0; i<1000000; ++i) {
file.write(QByteArray::number(rand()/1000.0, 'e') + " ");
file.write(QByteArray::number(rand()/1000.0, 'e') + " ");
file.write(QByteArray::number(rand()/1000.0, 'e') + "\n");
}
file.close();
qDebug("Starting Test");
// read
QTime time;
QList<QByteArray> cache;
file.open(QIODevice::ReadOnly | QIODevice::Text);
time.start();
for (int i=0; i<1000000; ++i) {
cache << file.readLine();
}
qDebug("readLine: %dms", time.elapsed());
file.close();
// convert
time.start();
for (int i=0; i<1000000; ++i) {
//parseLine(cache[i], i);
QByteArray line = cache[i].simplified();
QList<QByteArray> list = line.split(' ');
list[0].toDouble();
list[1].toDouble();
list[2].toDouble();
}
qDebug("toDouble: %dms", time.elapsed());
return 0;
}
Das ist jetzt nicht dynamisch sondern alles hart reingecoded, aber es ist ein gutes und realistisches Beispiel und so braucht das Parsen gut dreimal so lang wie das ReadLine auf meinem Laptop mit ner 5400rpm Platte und nem 1,73GHz Singlecore.
Die tatsächliche parseLine sieht ähnlich aus, nur halt dynamischer. Ich poste sie am Ende für die dies interessiert.
Ein Kumpel von mir hat mal einen Parser für das gleiche Problem in C geschrieben und der Geschwindigkeitsunterschied zur Qt-Lösung ist minimal (meist ist meiner wenige milisekunden schneller, aber wir haben auch beide noch ein paar postprocessing-Schritte mitgemessen. Wenn ich toDouble durch strtod ersetze quetsch ich tatsächlich noch 1 Prozent Performance raus aber hab keine ok-Variable mehr, und die brauch ich z.B.). Ich hab das ganze nochmal mit Qt geschrieben weil er ihn niemals fertiggestellt hat (War noch fast alles statisch dran, kaum dynamisch).
Hat mich auch verwundert, aber die Qt funktionen sind kaum langsamer als C. Daumen hoch, Trolle!
so, hier noch die ausführliche parseLine Funktion, vllt kommen dann ja endlich mal Tipps zum Topic...
Code: Alles auswählen
void Loader::parseLine(QByteArray rawLine, int nr) {
// strip comments and redundant separators and blanks
QByteArray line = simplified(rawLine, sepChar, comChar);
if (line.size() == 0) {
return;
}
QList<QByteArray> list = line.split(sepChar);
if (list.size() < minColumns) {
qWarning("Skipped line %d: Expected %d data items but only found %d. (%d: \"%s\")", nr, minColumns, list.size(), nr, line.data());
return;
}
bool ok;
Data* newData = new Data;
newData->x = list[xColumn-1].toDouble(&ok);
if (!ok) {
qWarning("Skipped line %d: X value (data item %d) is not a valid number. (%d: \"%s\")", nr, xColumn, nr, line.data());
delete newData;
return;
}
newData->y = list[yColumn-1].toDouble(&ok);
if (!ok) {
qWarning("Skipped line %d: Y value (data item %d) is not a valid number. (%d: \"%s\")", nr, yColumn, nr, line.data());
delete newData;
return;
}
double zTemp;
if (zColumns.isEmpty()) {
for (int i=0; i<list.size(); i++) {
if (i != (xColumn-1) && i != (yColumn-1)) {
zTemp = list[i].toDouble(&ok);
if (!ok) {
qWarning("Skipped line %d: Z value (data item %d) is not a valid number. (%d: \"%s\")", nr, i+1, nr, line.data());
delete newData;
return;
}
if (!newData->z.contains(zTemp)) {
newData->z << zTemp;
}
}
}
}
else {
for (int i=0; i<zColumns.size(); i++) {
zTemp = list[i].toDouble(&ok);
if (!ok) {
qWarning("Skipped line %d: Z value (data item %d) is not a valid number. (%d: \"%s\")", nr, zColumns[i], nr, line.data());
delete newData;
return;
}
if (!newData->z.contains(zTemp)) {
newData->z << zTemp;
}
}
}
appendCache(newData);
}
Und bevor noch weitere Fragen kommen hier noch ein paar aufgerufene Funktionen und so:
Code: Alles auswählen
struct Data {
double x;
double y;
QList<double> z;
};
QByteArray simplified(QByteArray in, char sep, char com) {
if (in.size() == 0)
return in;
QByteArray result(in.size(), ' ');
const char *from = in.data();
const char *fromend = from + in.size();
int outc = 0;
char *to = result.data();
forever {
while (from!=fromend && (*from==sep || isspace(uchar(*from))))
from++;
while (from!=fromend && ((*from!=sep && *from!=com) && !isspace(uchar(*from))))
to[outc++] = *from++;
if (from!=fromend && *from!=com)
to[outc++] = sep;
else
break;
}
if (outc > 0 && to[outc-1] == sep)
outc--;
result.resize(outc);
return result;
}
void MatrixLoader::appendCache(Data *newData) {
mutex->lock();
cacheList << newData;
mutex->unlock();
}