2017-01-03 1 views
1

Ich habe Feedback, dass diese Knotenfunktion Leistungsprobleme beim Abrufen der Zeilenanzahl einer Datei hat, aber nicht in der Lage, die genauen Details zu bestimmen.Node File Line Count

function countFileLines(filePath){ 
    return new Promise((resolve, reject) => { 
    let lineCount = 0; 
    fs.createReadStream(filePath) 
    .on("data", (buffer) => { 
     buffer.forEach((chunk) => { 
     if (chunk === 10) lineCount++; 
     }); 
    }).on("end",() => { 
     resolve(lineCount); 
    }).on("error", reject); 
    }); 
}; 

Gibt es eine performantere Möglichkeit, die Zeilenanzahl einer Datei in Node zu erhalten?

Antwort

1

Ich kann nur spekulieren, aber buffer.forEach eine Funktion aufrufen und einen Vergleich für jedes Byte tun könnte das Problem sein. Betrachten Sie indexOf mit der VM die Zeilenumbrüche für Sie lassen:

function countFileLines(filePath){ 
    return new Promise((resolve, reject) => { 
    let lineCount = 0; 
    fs.createReadStream(filePath) 
     .on("data", (buffer) => { 
     let idx = -1; 
     lineCount--; // Because the loop will run once for idx=-1 
     do { 
      idx = buffer.indexOf(10, idx+1); 
      lineCount++; 
     } while (idx !== -1); 
     }).on("end",() => { 
     resolve(lineCount); 
     }).on("error", reject); 
    }); 
}; 

Was diese Lösung macht, ist, dass sie die Position des ersten Newline findet .indexOf verwenden. Es erhöht lineCount, dann findet es die nächste Position. Der zweite Parameter zu .indexOf gibt an, wo Sie nach neuen Zeilen suchen müssen. Auf diese Weise springen wir über große Teile des Puffers. Die while-Schleife wird einmal für jede neue Zeile plus eins ausgeführt.

Wir lassen die Node Runtime die Suche nach uns, die auf einer niedrigeren Ebene implementiert ist und schneller sein sollte.

Auf meinem System ist das etwa doppelt so schnell wie das Ausführen einer for Schleife über die Pufferlänge auf einer großen Datei (111 MB).

+0

Funktioniert es effizienter, als wenn ich eine normale for-Schleife verwenden würde? –

+0

Ja. Ich habe es dreimal mit meiner Funktion versucht und dreimal mit der Antwort von Qiaosen auf demselben Rechner mit der gleichen Datei. Die schnellste Zeit für meine Funktion war 443 ms. Der schnellste mit ihren war 812 ms. –

+0

Verdammt, ich habe beide Antworten mit 2 großen Verzeichnissen verglichen; Beide Versionen sind ein bedeutender Schub, aber dein ist schneller. Die Logik ist nicht intuitiv, aber es ist brillant. Vielen Dank! –

3
function countFileLines(filePath){ 
    return new Promise((resolve, reject) => { 
    let lineCount = 0; 
    let i = 0; 
    fs.createReadStream(filePath) 
    .on("data", (buffer) => { 
     for (i = 0; i < buffer.length; ++i) { 
     if (buffer[i] == 10) lineCount++; 
     } 
    }).on("end",() => { 
     resolve(lineCount); 
    }).on("error", reject); 
    }); 
}; 

zum Vergleich:

original: node index.js 2.38s user 0.29s system 98% cpu 2.713 total

modifed: node index2.js 0.18s user 0.04s system 96% cpu 0.225 total