关于我来自哪里的一些背景信息。代码片段在最后。
如果可以,我更喜欢使用H2O之类的开源工具来进行超高性能的并行CSV文件读取,但是此工具在功能集中受到限制。我最终写了很多代码来创建数据科学管道,然后将其馈送到H2O集群以进行有监督的学习。
我通过从多处理库的池对象和映射函数中添加了很多并行性,从UCI仓库读取8GB HIGGS数据集的文件,甚至从数据中读取40GB CSV文件的速度也大大提高了。例如,使用最近邻居搜索进行聚类以及DBSCAN和Markov聚类算法都需要一些并行编程技巧,以绕过一些严重挑战性的内存和挂钟时间问题。
我通常喜欢先使用gnu工具将文件按行分成几部分,然后对所有文件进行glob-filemask,以在python程序中并行查找和读取它们。我通常使用1000多个部分文件。做这些技巧可以极大地提高处理速度和内存限制。
pandas dataframe.read_csv是单线程的,因此您可以执行以下技巧,通过运行map()并行执行来使pandas更快。您可以使用htop查看带有普通旧式顺序熊猫dataframe.read_csv的情况,仅一个内核上的100%cpu就是pd.read_csv中的实际瓶颈,而不是磁盘。
我应该补充一点,我在快速视频卡总线上使用SSD,而不是在SATA6总线上使用旋转高清硬盘,外加16个CPU内核。
另外,我发现在另一种应用程序中非常有用的另一种技术是并行CSV文件读取一个巨型文件中的所有文件,从而以不同的偏移量开始每个工作程序到文件中,而不是将一个大文件预分割为许多零件文件。在每个并行工作程序中使用python的文件seek()和tell()来读取条带中的大文本文件,这些文件位于大文件中不同的字节偏移起始字节和结束字节位置,并且同时进行。您可以对字节执行正则表达式findall,并返回换行计数。这是部分款项。最后,在工作人员完成后map函数返回时,将部分和求和以得到全局和。
以下是使用并行字节偏移技巧的一些示例基准测试:
我使用2个文件:HIGGS.csv是8 GB。它来自UCI机器学习存储库。all_bin .csv是40.4 GB,来自我当前的项目。我使用2个程序:Linux附带的GNU wc程序,以及我开发的纯python fastread.py程序。
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
那是大约4.5 GB / s或45 Gb / s的文件拖曳速度。我的朋友,那不是没有旋转的硬盘。那实际上是三星Pro 950 SSD。
以下是由纯C编译程序gnu wc进行行计数的同一文件的速度基准。
很酷的是,在这种情况下,您可以看到我的纯python程序与gnu wc编译的C程序的速度基本匹配。Python是可解释的,但C是已编译的,因此这是一个非常有趣的壮举,我想您会同意的。当然,wc确实需要更改为并行程序,然后才能真正击败我的python程序。但是就目前而言,gnu wc只是一个顺序程序。您可以尽力而为,而python今天可以并行完成。Cython编译可能会帮助我(另一些时间)。此外,还没有探索内存映射文件。
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
结论:与C程序相比,纯python程序的速度不错。但是,至少在行计数方面,仅在C程序上使用纯python程序是不够的。通常,该技术可用于其他文件处理,因此此python代码仍然不错。
问题:仅一次编译正则表达式并将其传递给所有工作人员是否会提高速度?答:Regex预编译在此应用程序中无济于事。我想原因是所有工人的过程序列化和创建的开销占主导。
还有一件事。并行读取CSV文件是否有帮助?磁盘是瓶颈,还是CPU?他们说,许多关于stackoverflow的最受好评的答案都包含着通用的开发智慧,即您只需要一个线程即可读取文件,并且可以做到最好。他们确定吗?
让我们找出:
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
哦,是的,是的。并行文件读取效果很好。好吧,你去!
附言 如果您想知道某些情况,那么在使用单个工作进程时,如果balanceFactor为2,该怎么办?好吧,这太可怕了:
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
fastread.py python程序的关键部分:
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
PartitionDataToWorkers的def只是普通的顺序代码。我省去了它,以防其他人想对并行编程的方式有所了解。我免费提供了更难的部分:经过测试和运行的并行代码,以帮助您学习。
感谢:Arno和Cliff的开源H2O项目以及H2O员工的出色软件和指导视频,它们为我提供了如上所述的纯Python高性能并行字节偏移读取器的灵感。H2O使用Java进行并行文件读取,可被python和R程序调用,并且在读取大型CSV文件方面比在地球上任何东西都快,而且速度惊人。