2017-02-09 10 views
2

Ich habe Hunderte von Gigabyte Daten in Binärdateien. Ich möchte eine zufällige Stichprobe der Daten nehmen und viele aufeinanderfolgende Datensätze mehrmals zufällig lesen.Datei in parallelen Stapeln aus Python lesen

Die Daten werden in vielen Dateien gespeichert. Die Hauptdateien speichern die Daten nicht in einer bestimmten Reihenfolge, daher hat jede eine sortierte Indexdatei. Mein aktueller Code ist etwas ähnliches, außer dass es viele Dateien gibt:

Dann werden andere Dinge mit den Aufzeichnungen gemacht. Beim Profiling sehe ich, dass das Programm stark IO-gebunden ist und die meiste Zeit in und data.read verbracht wird. Ich vermute, das liegt daran, dass read blockiert: Der Interpreter wartet darauf, dass das Betriebssystem die Daten von der Festplatte liest, bevor er nach dem nächsten zufälligen Datenblock fragt, sodass das Betriebssystem keine Gelegenheit hat, das Festplattenzugriffsmuster zu optimieren. Also: Gibt es eine Datei-API, an die ich eine Reihe von Anweisungen weitergeben kann? Etwas wie:

def read_many(file, offsets, lengths): 
    ''' 
    @param file: the file to read from 
    @param offsets: the offsets to seek to 
    @param lengths: the lengths of data to read 
    @return an iterable over the file contents at the requested offsets 
    ''' 

Alternativ wäre es genug sein, mehrere Dateiobjekte zu öffnen und Anforderung mehr liest Multithreading mit? Oder würde die GIL verhindern, dass das nützlich ist?

+1

Relevant: https://stackoverflow.com/questions/29270818/why-is-a-python-i-o-bound-task-not-blocked-by-the-gil. – ekhumoro

+0

Was sind die minimalen, maximalen und mittleren Größen der Dateien? – Apalala

Antwort

3

Da die Prozesse IO-gebunden sind, wird die Grenze für die Lesevorgänge vom Datenträgeroperationsplaner des Betriebssystems und vom Cache der Festplatte festgelegt.

Actual, pro-Kern kann Parallelisierung leicht mit multiprocessing.Pool.imap_unordered() gehabt werden:

def pmap(fun, tasks): 
    from multiprocessing import Pool 
    with Pool() as pool: 
     yield from pool.imap_unordered(fun, tasks) 

for record_set in pmap(process_one_file, filenames): 
    print(record_set) 

mehrere Dateien öffnen zur gleichen Zeit zu haben, und wahrscheinlich ein read() von jedem Kern ausgeführt wird, sollte die Platte Scheduler Figur erlauben einen Zeitplan, der besser ist als der serielle, der von der Liste der Dateinamen auferlegt wird.

Die Schönheit von imap_unordered() ist, dass es post-processing entkoppelt von, wie, und warum eine Aufgabe früher als die andere beendet (die Reihenfolge kann bei verschiedenen Läufen anders sein).

Wie in den Kommentaren erwähnt, ist die GIL nur während der Ausführung von Python-Code beteiligt, was nicht der Fall für ein Programm ist, das auf I/O blockiert.