关于我来自哪里的一些背景信息。代码片段在最后。
如果可以的话,我更喜欢使用像 H2O 这样的开源工具来进行超高性能的并行 CSV 文件读取,但是这个工具在功能集上是有限的。我最终编写了大量代码来创建数据科学管道,然后再将其馈送到 H2O 集群以进行适当的监督学习。
我一直在读取来自 UCI 存储库的 8GB HIGGS 数据集,甚至是用于数据科学目的的 40GB CSV 文件,通过使用多处理库的池对象和映射函数添加大量并行性,速度明显更快。例如,最近邻搜索的聚类以及 DBSCAN 和 Markov 聚类算法需要一些并行编程技巧来绕过一些严重具有挑战性的内存和挂钟时间问题。
我通常喜欢首先使用 gnu 工具将文件按行分成几部分,然后将它们全部 glob-filemask 以在 python 程序中并行查找和读取它们。我通常使用 1000 多个部分文件。使用这些技巧可以极大地提高处理速度和内存限制。
pandas dataframe.read_csv 是单线程的,因此您可以通过运行 map() 并行执行这些技巧来使 pandas 更快。您可以使用 htop 看到,对于普通的旧顺序 pandas dataframe.read_csv,只有一个核心上的 100% cpu 是 pd.read_csv 中的实际瓶颈,而不是磁盘。
我应该补充一下,我在快速视频卡总线上使用 SSD,而不是在 SATA6 总线上使用旋转 HD,以及 16 个 CPU 内核。
此外,我发现在某些应用程序中效果很好的另一种技术是并行 CSV 文件读取一个大文件中的所有内容,以不同的偏移量启动每个工作程序到文件中,而不是将一个大文件预先拆分为多个部分文件。在每个并行工作程序中使用 python 的文件 seek() 和 tell() 以条状读取大文本文件,在大文件中不同的字节偏移开始字节和结束字节位置,同时同时进行。您可以对字节执行正则表达式查找,并返回换行数。这是部分金额。最后在worker完成后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 的文件 slurping 速度。那不是没有旋转的硬盘,我的朋友。那实际上是三星 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 只是普通的顺序代码。我把它留了下来,以防其他人想练习一下并行编程是什么样的。我免费赠送了更难的部分:经过测试和工作的并行代码,以供您学习。
感谢:开源 H2O 项目,由 Arno 和 Cliff 以及 H2O 工作人员提供的出色软件和教学视频,为我提供了如上所示的纯 Python 高性能并行字节偏移阅读器的灵感。H2O 使用 java 进行并行文件读取,可由 python 和 R 程序调用,并且速度非常快,在读取大型 CSV 文件时比地球上任何东西都快。