Ein Zusammenhang im Vorfeld, woher ich komme. Code-Schnipsel sind am Ende.
Wenn ich kann, bevorzuge ich die Verwendung eines Open-Source-Tools wie H2O, um parallele CSV-Dateilesevorgänge mit hoher Leistung durchzuführen. Dieses Tool ist jedoch in seinen Funktionen eingeschränkt. Am Ende schreibe ich viel Code, um Data Science-Pipelines zu erstellen, bevor ich sie für das überwachte Lernen in den H2O-Cluster einspeise.
Ich habe Dateien wie 8 GB HIGGS-Dataset von UCI Repo und sogar 40 GB CSV-Dateien für datenwissenschaftliche Zwecke erheblich schneller gelesen, indem ich viel Parallelität mit dem Poolobjekt und der Kartenfunktion der Multiprozessor-Bibliothek hinzugefügt habe. Zum Beispiel erfordert das Clustering mit Suchvorgängen für den nächsten Nachbarn sowie DBSCAN- und Markov-Clustering-Algorithmen einige parallele Programmierfinesse, um einige ernsthaft herausfordernde Speicher- und Wanduhrzeitprobleme zu umgehen.
Normalerweise teile ich die Datei gerne zeilenweise mit Gnu-Tools in Teile auf und maskiere sie dann alle, um sie parallel im Python-Programm zu finden und zu lesen. Ich verwende üblicherweise mehr als 1000 Teildateien. Das Ausführen dieser Tricks hilft immens bei der Verarbeitungsgeschwindigkeit und den Speicherbeschränkungen.
Der pandas dataframe.read_csv ist ein Single-Thread, sodass Sie diese Tricks ausführen können, um Pandas schneller zu machen, indem Sie eine map () für die parallele Ausführung ausführen. Sie können htop verwenden, um zu sehen, dass bei einfachen alten sequentiellen Pandas dataframe.read_csv 100% CPU auf nur einem Kern der eigentliche Engpass in pd.read_csv ist, nicht auf der Festplatte.
Ich sollte hinzufügen, dass ich eine SSD auf einem schnellen Grafikkartenbus verwende, keine sich drehende HD auf einem SATA6-Bus sowie 16 CPU-Kerne.
Eine andere Technik, von der ich herausgefunden habe, dass sie in einigen Anwendungen hervorragend funktioniert, ist das parallele Lesen von CSV-Dateien innerhalb einer riesigen Datei, wobei jeder Worker mit einem unterschiedlichen Versatz in die Datei gestartet wird, anstatt eine große Datei in viele Teiledateien vorab aufzuteilen. Verwenden Sie Pythons Dateisuche () und tell () in jedem parallelen Worker, um die große Textdatei in Streifen an verschiedenen Start- und Endbytepositionen des Byteversatzes in der großen Datei gleichzeitig zu lesen. Sie können eine Regex-Suche für die Bytes durchführen und die Anzahl der Zeilenvorschübe zurückgeben. Dies ist eine Teilsumme. Summieren Sie schließlich die Teilsummen, um die globale Summe zu erhalten, wenn die Kartenfunktion nach Beendigung der Arbeit zurückkehrt.
Im Folgenden finden Sie einige Beispielbenchmarks, die den Parallel-Byte-Offset-Trick verwenden:
Ich benutze 2 Dateien: HIGGS.csv ist 8 GB. Es stammt aus dem UCI-Repository für maschinelles Lernen. all_bin .csv ist 40,4 GB groß und stammt aus meinem aktuellen Projekt. Ich benutze 2 Programme: das mit Linux gelieferte GNU wc-Programm und das von mir entwickelte reine Python fastread.py-Programm.
HP-Z820:/mnt/fastssd/fast_file_reader$ ls -l /mnt/fastssd/nzv/HIGGS.csv
-rw-rw-r-- 1 8035497980 Jan 24 16:00 /mnt/fastssd/nzv/HIGGS.csv
HP-Z820:/mnt/fastssd$ ls -l all_bin.csv
-rw-rw-r-- 1 40412077758 Feb 2 09:00 all_bin.csv
ga@ga-HP-Z820:/mnt/fastssd$ time python fastread.py --fileName="all_bin.csv" --numProcesses=32 --balanceFactor=2
2367496
real 0m8.920s
user 1m30.056s
sys 2m38.744s
In [1]: 40412077758. / 8.92
Out[1]: 4530501990.807175
Das sind etwa 4,5 GB / s oder 45 Gbit / s, die Geschwindigkeit beim Schlürfen von Dateien. Das ist keine sich drehende Festplatte, mein Freund. Das ist eigentlich eine Samsung Pro 950 SSD.
Unten finden Sie den Geschwindigkeits-Benchmark für dieselbe Datei, die von gnu wc, einem reinen C-kompilierten Programm, zeilenweise gezählt wird.
Was cool ist, ist, dass mein reines Python-Programm in diesem Fall im Wesentlichen der Geschwindigkeit des von gnu wc kompilierten C-Programms entspricht. Python wird interpretiert, aber C wird kompiliert, daher ist dies eine ziemlich interessante Leistung, ich denke, Sie würden dem zustimmen. Natürlich muss wc wirklich in ein paralleles Programm geändert werden, und dann würde es wirklich die Socken von meinem Python-Programm schlagen. Aber so wie es heute ist, ist gnu wc nur ein sequentielles Programm. Sie tun, was Sie können, und Python kann heute parallel tun. Das Kompilieren von Cython kann mir möglicherweise helfen (für eine andere Zeit). Auch Speicherzuordnungsdateien wurden noch nicht untersucht.
HP-Z820:/mnt/fastssd$ time wc -l all_bin.csv
2367496 all_bin.csv
real 0m8.807s
user 0m1.168s
sys 0m7.636s
HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000
real 0m2.257s
user 0m12.088s
sys 0m20.512s
HP-Z820:/mnt/fastssd/fast_file_reader$ time wc -l HIGGS.csv
11000000 HIGGS.csv
real 0m1.820s
user 0m0.364s
sys 0m1.456s
Fazit: Die Geschwindigkeit ist für ein reines Python-Programm im Vergleich zu einem C-Programm gut. Es ist jedoch nicht gut genug, das reine Python-Programm über dem C-Programm zu verwenden, zumindest nicht für die Zählung. Im Allgemeinen kann die Technik für andere Dateiverarbeitungen verwendet werden, sodass dieser Python-Code immer noch gut ist.
Frage: Verbessert das einmalige Kompilieren des regulären Ausdrucks und das Weitergeben an alle Mitarbeiter die Geschwindigkeit? Antwort: Die Vorkompilierung von Regex hilft in dieser Anwendung NICHT. Ich nehme an, der Grund dafür ist, dass der Aufwand für die Serialisierung und Erstellung von Prozessen für alle Mitarbeiter dominiert.
Eine Sache noch. Hilft das parallele Lesen von CSV-Dateien überhaupt? Ist die Festplatte der Engpass oder die CPU? Viele sogenannte Top-Antworten auf Stackoverflow enthalten die allgemeine Entwickler-Weisheit, dass Sie nur einen Thread benötigen, um eine Datei zu lesen. Das Beste, was Sie tun können, heißt es. Sind sie sich aber sicher?
Lass es uns herausfinden:
HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000
real 0m2.256s
user 0m10.696s
sys 0m19.952s
HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=1
11000000
real 0m17.380s
user 0m11.124s
sys 0m6.272s
Oh ja, ja, das tut es. Das parallele Lesen von Dateien funktioniert recht gut. Na siehst du!
Ps. Falls einige von Ihnen wissen wollten, was wäre, wenn der balanceFactor bei Verwendung eines einzelnen Worker-Prozesses 2 wäre? Nun, es ist schrecklich:
HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=2
11000000
real 1m37.077s
user 0m12.432s
sys 1m24.700s
Wichtige Teile des Python-Programms fastread.py:
fileBytes = stat(fileName).st_size # Read quickly from OS how many bytes are in a text file
startByte, endByte = PartitionDataToWorkers(workers=numProcesses, items=fileBytes, balanceFactor=balanceFactor)
p = Pool(numProcesses)
partialSum = p.starmap(ReadFileSegment, zip(startByte, endByte, repeat(fileName))) # startByte is already a list. fileName is made into a same-length list of duplicates values.
globalSum = sum(partialSum)
print(globalSum)
def ReadFileSegment(startByte, endByte, fileName, searchChar='\n'): # counts number of searchChar appearing in the byte range
with open(fileName, 'r') as f:
f.seek(startByte-1) # seek is initially at byte 0 and then moves forward the specified amount, so seek(5) points at the 6th byte.
bytes = f.read(endByte - startByte + 1)
cnt = len(re.findall(searchChar, bytes)) # findall with implicit compiling runs just as fast here as re.compile once + re.finditer many times.
return cnt
Die Definition für PartitionDataToWorkers ist nur gewöhnlicher sequentieller Code. Ich habe es weggelassen, falls jemand anderes etwas üben möchte, wie paralleles Programmieren ist. Ich habe die schwierigeren Teile kostenlos verschenkt: den getesteten und funktionierenden Parallelcode, zu Ihrem Lernvorteil.
Dank an: Das Open-Source-H2O-Projekt von Arno und Cliff und den H2O-Mitarbeitern für ihre großartige Software und Lehrvideos, die mich wie oben gezeigt zu diesem reinen Python-Hochleistungs-Parallelbyte-Offset-Lesegerät inspiriert haben. H2O liest parallel Dateien mit Java, kann von Python- und R-Programmen aufgerufen werden und ist verrückt schnell und schneller als alles andere auf der Welt beim Lesen großer CSV-Dateien.