Die naheliegende Lösung besteht darin, die Eingabe in Blöcken zu verarbeiten. Wenn Sie dies tun können, hat dies den zusätzlichen Vorteil, dass Sie Berechnungen (auf dem aktuellen Block) während der I/O durchführen können (die meisten Betriebssysteme führen Lookahead-Pufferungen durch), was zu einer kürzeren realen Zeit führt als das erste Lesen aller Daten , dann verarbeitet es in einem Stück.
(Ich erwähne oft diese Tatsache für diejenigen, die ein sort
-Typ-Dienstprogramm implementieren. Für echte, messbare Beschleunigungen, sollten Sie die Eingaben in einen Baum, anstatt in ein Array lesen und dann das Array sortieren, weil Der Speicher ist langsam, und wenn Sie jeden Eingangsdatensatz (Zeile) sofort in einen Baum einfügen, können Sie im Prinzip die Zeit nutzen, die sonst für das Sortieren der Daten auf E/A benötigt wird Implementierung) im Vergleich zu einem wirklich guten Array Sortieralgorithmus, aber die Menschen kümmern sich nicht oft viel darüber. Wir kümmern uns hauptsächlich um reale Welt Wartezeit verbracht haben. Wir möchten nicht warten.)
Wenn die Auf Eingabedatensätze (Zeilen) wird zufällig zugegriffen, und Sie arbeiten an einer 64-Bit-Architektur, Speichermapping-Techniken können es möglich machen. (Wenn Sie können tun die Arbeit in Chunks, tun Sie dies, wenn Sie nicht können, Speicherzuordnung können Sie die Verarbeitung auch wenn Sie nicht genügend RAM haben.)
Vor Jahren schrieb ich ein minimales Beispiel auf wie Sie eine Datei-abgesicherte Sparse-Speicherzuordnung in 64-Bit-Linux zu manipulate a terabyte data structure verwenden.
In diesem Fall können Sie eine schreibgeschützte Speicherzuordnung für den wahlfreien Zugriff auf die Textdatei verwenden. Beachten Sie, dass Sie in Linux mmap(NULL, aligned_length, PROT_READ, MAP_SHARED | MAP_NORESERVE, fd, 0)
verwenden sollten, wobei aligned_length
die Länge der Textdatei ist, die auf das nächste Vielfache von sysconf(SC_PAGESIZE)
aufgerundet wird. Solche Zuordnungen verwenden keinen Swap (und daher begrenzt die Größe des Swap-Space nicht die Größe des Mappings), aber der Kernel kann und wird die Seiten löschen (und bei Bedarf aus der Datei selbst erneut lesen), wenn der Speicher zu knapp ist.
Eine zweite Speicherzuordnung kann zum Speichern der Offsets (bei 64-Bit-Architekturen size_t
ist ausreichend groß) am Anfang jeder Zeile verwendet werden. Diese Zuordnung sollte mmap(NULL, offbufsize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd2, 0)
verwenden, wobei offbufsize
ein Vielfaches von sysconf(_SC_PAGESIZE)
ist, aber mindestens so groß wie die Anzahl der Zeilen in der Eingabedatei, multipliziert mit sizeof (size_t)
.
Die Bestimmung des Anfangs jeder Zeile ist eine Operation, die am besten in Chunks (von 512 × 1024 = 524288 Bytes) durchgeführt wird. Das heißt, Sie sollten zuerst das zweite Mapping einrichten, indem Sie ftruncate()
und mremap()
verwenden, um es bei Bedarf zu vergrößern, indem Sie die erste Datei mit Low-Level-E/A (unistd.h read()
) in den oben genannten Abschnitten lesen, um den Anfang jeder Zeile zu bestimmen.
Ich persönlich habe etwas Ähnliches in der Praxis gemacht. Selbst mit universeller Newline-Unterstützung (unterstützt \r\n
oder CRLF, \n\r
oder LFCR, \r
oder CR, und \n
oder LF, gleichzeitig, automatisch) benötigen Sie nur ein paar zusätzliche Bytes Speicherplatz im Array zum Speichern des Chunk gelesen aus der großen Textdatei. Da der Initial Pass vollständig linear ist, kann die Verwendung von posix_fadvise(fd,0,0,POSIX_FADV_NOREUSE)
oder posix_fadvise(fd,0,0,POSIX_FADV_SEQUENTIAL)
gerechtfertigt sein.
Angesichts mindestens ein paar Gigabyte RAM zur Pufferung zur Verfügung (was als eine typische Situation sogar auf kleineren 64-Bit-Linux/POSIX-Workstations gilt), obwohl das Linux-Kernel-Paging-Zeug nicht "magisch" ist überraschend gut.
Der häufigste Grund für unbefriedigende Leistung mit viel-größer-als-verfügbaren RAM-Mappings, die ich in Linux gesehen habe, ist das Vergessen der MAP_NORESERVE
Flagge. Dies führt zu unnötigen Einschränkungen (verfügbarer Swap-Speicherplatz, der die maximal zulässige Mapping-Größe begrenzt) sowie zu schlechter Leistung bei knappem Speicher (da die Seiten zum Austauschen geschrieben sind und nicht einfach in den Boden fallen).
lesen Sie es nach kleineren Zeilenblöcken. –
Wie Sie bereits gesagt haben, können Sie jeweils eine Zeile lesen, sie verarbeiten und dann für die verbleibenden Datenzeilen dasselbe tun. – ameyCU
Sie haben sich selbst geantwortet. Stück für Stück ist der richtige Weg –