2009-04-09 13 views
11

Ich schreibe ein Programm, in dem Leistung ziemlich wichtig ist, aber nicht kritisch. Momentan lese ich Zeile für Zeile einen Text von einer FILE* und benutze fgets, um jede Zeile zu erhalten. Nach der Verwendung einiger Leistungstools habe ich festgestellt, dass 20% bis 30% der Zeit, in der meine Anwendung ausgeführt wird, innerhalb von fgets liegen.Eine Eingabezeile schneller lesen als fgets?

Gibt es schnellere Möglichkeiten, eine Textzeile zu erhalten? Meine Anwendung ist single-threaded ohne Absicht mehrere Threads zu verwenden. Die Eingabe kann von der Standardeingabe oder von einer Datei erfolgen. Danke im Voraus.

+0

Was ist die durchschnittliche Länge (und mögliche stdev) der Zeilen, die Ihr Programm analysiert? Dies hilft, den schnellsten Weg zu finden, auf sie zuzugreifen. – Juliano

+0

@Juliano, die Zeilen sind immer weniger als 260 Zeichen lang. Ich habe bereits eine Leitungsaufbau-Schleife vermieden. – dreamlax

+0

Kontrollieren Sie das Eingabeformat? Könnten Sie es kompakter machen? – Dave

Antwort

7

Sie sagen nicht, auf welcher Plattform Sie sich befinden, aber wenn es UNIX-ähnlich ist, können Sie den Systemaufruf read() versuchen, der die zusätzliche Pufferschicht fgets() et nicht ausführt al do. Dies kann die Dinge etwas beschleunigen, andererseits kann es die Dinge verlangsamen - der einzige Weg, es herauszufinden, ist, es zu saugen und zu sehen.

+0

Dies erwies sich als die schnellste Methode von allen. Ich ging schließlich diese Route hinunter. Es war einfacher als ich gedacht hatte "meine eigene Pufferung" und es stellte sich heraus, dass es viel, viel schneller (fast 4-mal) war als mit "fgets()". – dreamlax

+0

Ironischerweise, für mich preadomed 4 mal schlimmer als fgets. – abirvalg

2

Wenn die Daten von der Festplatte kommen, könnten Sie IO-gebunden sein.

Wenn das der Fall ist, besorgen Sie sich einen schnelleren Datenträger (aber prüfen Sie zuerst, ob Sie das Beste aus Ihrem bestehenden herausholen ... einige Linux-Distributionen optimieren den Festplattenzugriff nicht sofort (hdparm)) , stapeln Sie die Daten vorher in den Speicher (sagen Sie, indem Sie sie auf eine RAM-Disk kopieren) oder seien Sie bereit zu warten.


Wenn Sie nicht IO gebunden sind, könnten Sie eine Menge Zeit mit dem Kopieren verschwenden. Sie könnten von sogenannten Nullkopie-Methoden profitieren. So etwas wie Speicher mappen die Datei und greifen nur über Zeiger darauf zu.

Das ist ein bisschen über meine Sachkenntnis hinaus, also sollten Sie etwas lesen oder auf sachkundigere Hilfe warten.

BTW-- Sie könnten in mehr Arbeit kommen, als das Problem wert ist; vielleicht eine schnellere Maschine würde lösen alle Probleme ...

NB-- Es ist nicht klar, dass Sie Speicher, um die Standardeingabe Karte kann entweder ...

+0

Manchmal kommt es von der Festplatte, manchmal wird es durch stdin gespeist, aber in beiden Fällen ist die Zeit, die in Fgets verbracht wird, in etwa gleich. Selbst das Erstellen einer RAM-Disk für die Datei beschleunigt die Dinge nicht viel. – dreamlax

+0

Nach dem Bearbeiten: Das Problem ist, dass diese Anwendung auf dem Computer des Endbenutzers ausgeführt wird, deshalb ist die Leistung sehr wichtig. – dreamlax

3

Sie könnten die Zeit, versuchen zu minimieren Lesen Sie verbringen von der Festplatte durch das Lesen großer Datenmengen in RAM und dann daran arbeiten. Das Lesen von der Festplatte ist langsam, also minimieren Sie die Zeit, die Sie damit verbringen, indem Sie (idealerweise) die gesamte Datei einmal lesen und dann daran arbeiten.

Sorta wie die Art und Weise wie CPU-Cache die Zeit minimiert, die die CPU tatsächlich in den Arbeitsspeicher zurückkehrt, könnten Sie RAM verwenden, um die Anzahl der tatsächlichen Arbeitsvorgänge zu minimieren.

+0

Stdio ist bereits gepuffert, oder? –

+0

Ich denke schon, aber ich bin mir sicher, dass es weniger als ein Megabyte ist, also sollte das Lesen mehr als das noch helfen. – GManNickG

2

Abhängig von Ihrer Umgebung kann die Verwendung von setvbuf() zur Erhöhung der Größe des von Dateiströmen verwendeten internen Puffers die Leistung verbessern oder nicht.

Dies ist die Syntax -

setvbuf (InputFile, NULL, _IOFBF, BUFFER_SIZE); 

Wo Eingabedatei ein FILE * in eine Datei gerade geöffnet ist mit fopen() und BUFFER_SIZE ist die Größe des Puffers (die für Sie von diesem Anruf zugeordnet ist).

Sie können verschiedene Puffergrößen ausprobieren, um festzustellen, ob sie einen positiven Einfluss haben. Beachten Sie, dass dies völlig optional ist und Ihre Laufzeitumgebung mit diesem Aufruf absolut nichts anfangen kann.

4
  1. Verwendung fgets_unlocked(), aber sorgfältig lesen, was sie tut erste

  2. die Daten mit fgetc() oder fgetc_unlocked() anstelle von fgets() Liefert.Mit fgets() werden Ihre Daten zweimal in den Speicher kopiert, zuerst von der C-Laufzeitbibliothek von einer Datei in einen internen Puffer (Stream-E/A wird gepuffert), dann von diesem internen Puffer zu einem Array in Ihrem Programm

+0

Danke für den Vorschlag, aber ich habe vergessen zu erwähnen, dass ich Mac OS X benutze. Fgets_unlocked ist nicht verfügbar, da es eine GNU-Erweiterung ist. Ich werde in die Verwendung von fgetc_unlocked schauen. – dreamlax

+0

Nun, OS X läuft GCC, Sie sollten die GNU-Erweiterungen bekommen, oder? –

+1

@Martin: Es ist keine Erweiterung des GNU-Compilers, sondern die GNU C-Laufzeitbibliothek. – dreamlax

4

Lesen Sie die gesamte Datei auf einmal in einen Puffer.

Verarbeiten Sie die Zeilen aus diesem Puffer.

Das ist die schnellstmögliche Lösung.

0

Wenn das Betriebssystem dies unterstützt, können Sie das asynchrone Lesen von Dateien versuchen, das heißt, die Datei wird in den Speicher gelesen, während die CPU anderweitig beschäftigt ist. So geht der Code so etwas wie: ​ ​ ​ ​ ​

start asynchronous read 
loop: 
    wait for asynchronous read to complete 
    if end of file goto exit 
    start asynchronous read 
    do stuff with data read from file 
    goto loop 
exit: 

Wenn Sie mehr als eine CPU haben dann eine CPU die Datei liest und analysiert die Daten in Zeilen, die andere CPU jede Zeile nimmt und verarbeitet sie .

0

Schauen Sie sich fread() an. Es liest sich viel schneller für mich, vor allem, wenn der Puffer für fread auf 65536 eingestellt ist. Nachteile: Sie müssen viel arbeiten und im Wesentlichen Ihre eigene getline-Funktion schreiben, um vom binären Lesen in den Text zu konvertieren. Auschecken: file I/O