20GB
,其中包含超过20百万行,每一行都代表一个单独的序列化JSON。像普通的循环那样
逐行读取
文件,并对每行数据进行操作需要很长时间。是否有任何
先进的
方法或最佳实践
,可以使用较小的块并以并行方式读取大型文件,以使处理更快?我正在使用Python 3.6.X。
20GB
,其中包含超过20百万行,每一行都代表一个单独的序列化JSON。逐行读取
文件,并对每行数据进行操作需要很长时间。先进的
方法或最佳实践
,可以使用较小的块并以并行方式读取大型文件,以使处理更快?使用另一种文件格式。从文本中读取序列化的json不是世界上最快的操作。因此,您可以存储数据(例如在hdf5中),这可以加快处理速度。
实现多个工作进程,它们可以读取文件的部分内容(worker1读取0-100万行,worker2读取100万-200万行等)。您可以使用joblib或celery进行编排,具体取决于您的需求。整合结果是挑战,您必须看看您的需求是什么(map-reduce风格?)。由于Python没有真正的线程,因此在Python中比在其他语言中更难,因此您可以为此切换语言。
在这里,你需要注意的主要瓶颈不是磁盘也不是CPU,而是内存。不是你拥有多少内存,而是硬件和操作系统如何协同工作,将页面从RAM预取到L{1,2,3}缓存中。
如果你使用readline()逐行加载数据,则并行方法的性能会比串行方法更差。原因与硬件+操作系统有关,而不是软件。当CPU需要读取内存时,一定数量的额外数据会被提前获取到CPU的Lx缓存中,以防这些数据稍后可能会被使用。当你采用串行方法时,这些额外数据实际上在缓存中使用。但是当并行readlines()发生时,额外数据在使用之前就被抢占了。因此,它必须稍后再次获取。这对性能有巨大影响。
使并行方法超越串行readline()方法的性能的方法是让并行进程一次读取多行数据到内存中。使用read()而不是readline()。你应该读取多少字节呢?大约是你的L1缓存大小,大约为64K。这样,几页连续的内存可以加载到该缓存中。
然而,如果你用串行的readline()替换成串行的read(),这将优于并行读取。为什么?因为虽然每个核心都有自己的L1缓存,但是核心共享其他L缓存,因此你会遇到同样的问题。进程1将预取以填充缓存,但在它处理完所有数据之前,进程2接管并替换了缓存内容。因此,进程1稍后必须再次获取相同的数据。
串行和并行之间的性能差异可以很容易地看出来: 首先确保整个文件在页面缓存中(free -m:buff/cache)。通过这样做,您完全从方程式中删除了磁盘/块设备层。整个文件都在RAM中。 然后运行一个简单的串行代码并计时。 然后运行一个简单的使用Process()的并行代码并计时。在商品系统上,串行读取将优于并行读取。
这与您的预期相反,对吧?但您必须考虑您所做的假设。您的假设并没有包括有多个核心之间共享的高速缓存和内存总线。这正是瓶颈所在的地方。我们知道磁盘不是瓶颈,因为我们已经将整个文件加载到了RAM的页面缓存中。我们知道CPU不是瓶颈,因为我们正在使用multiprocessing.Process()确保同时执行,每个核心一个进程(vmstat 1,top -d 1%1)。