多处理这么慢

Multiprocessing so slow

我有一个函数可以执行以下操作:

这是示例代码:

def extract_function(filename):  
   with open(filename,'r') as f:  
       input_data=f.readlines()  
   try:
     // some basic searching pattern matching extracting  
     // dataframe creation with 10 columns and then extracted values are filled in
        empty dataframe
     // finally df.to_csv()

if __name__ == '__main__':
   pool_size = multiprocessing.cpu_count()
   filenames=os.listdir("/home/Desktop/input")
   pool=multiprocessing.Pool(pool_size)
   pool.map(extract_function,filenames)
   pool.close()
   pool.join()

input 文件夹中的文件总数为 4000。我使用了多处理,因为 运行 通常使用 for 循环 的程序需要一些时间。以下是两种方法的执行时间:

Normal CPU processing = 139.22 seconds
Multiprocessing = 18.72 seconds

我的系统规格是:

Intel i5 7th gen, 12gb ram, 1Tb hdd, Ubuntu 16.04

虽然 运行 4000 个文件的程序所有内核都得到充分利用(平均每个内核约 90%)。所以我决定增加文件大小并重复该过程。这次输入文件数从 4000 增加到 1,20,000。但是这一次 运行 代码 cpu 的使用率在开始时不稳定,一段时间后利用率下降(每个内核的平均使用率约为 10%)。 ram 利用率也很低,平均最大为 4gb(剩余 8gb 可用)。使用 4000 个文件作为输入,文件写入 csv 的速度非常快,我可以在瞬间看到一个跳跃或大约 1000 个文件或更多文件。但是当输入 1,20,000 个文件时,文件写入速度减慢到大约 300 个文件,并且这种减慢速度呈线性下降,一段时间后文件写入速度瞬间变为 50-70 左右。一直以来,大部分 ram 都是免费的。我重新启动机器并尝试清除任何不需要的僵尸进程,但结果仍然相同。

这是什么原因? 如何对大文件实现相同的多处理?

注:
* 每个文件大小平均在 300kb 左右。
* 正在写入的每个输出文件将约为 200 字节。
* 文件总数为 4080。因此总大小为 ~1.2gb。
* 同样的 4080 个文件被用来制作副本以获得 1,20,000 个文件。
* 本程序是检查大量文件多处理的实验。

更新 1

我在功能更强大的机器上尝试过相同的代码。

Intel i7 8th gen 8700, 1Tb SSHD & 60gb ram.

。文件写入比普通硬盘快得多。该程序花费了:

在实验的某个时间点,我得到最快的完成时间是84秒。在那个时间点,它在连续两次尝试时给了我一致的结果。想着可能是我在pool size中正确设置了thread factor的数量,我重启了再试。但这一次慢多了。举个例子,在正常运行期间,大约 3000-4000 个文件将在一两秒内写入,但这次它在一秒钟内写入了 600 个文件以下。在这种情况下,ram 也根本没有被使用。 CPU 即使正在使用多处理模块,所有内核的平均利用率也只有 3-7% 左右。

与来自 RAM 的 运行 代码和数据相比,从磁盘读取和写入磁盘速度较慢。与来自 CPU.

内部缓存的 运行 代码和数据相比,它 极其

为了加快速度,使用了多个缓存。

  1. 硬盘一般都有内置缓存。 2012 年,我对此进行了一些编写测试。禁用硬盘的写入缓存后,写入速度从 72 MiB/s 下降到 12 MiB/s.
  2. 如今大多数操作系统都使用未占用的 RAM 作为磁盘缓存。
  3. CPU 也有几级内置缓存。

(通常有一种方法可以禁用缓存 1 和 2。如果您尝试这样做,您会发现读写速度急剧下降。)

所以我的猜测是,一旦传递了一定数量的文件,就会耗尽一个或多个缓存,磁盘 I/O 成为瓶颈。

要验证,您必须将代码添加到 extract_function 以衡量 3 件事:

  • 从磁盘读取数据需要多长时间。
  • 计算需要多长时间。
  • 写入 CSV 需要多长时间。

extract_function return 这三个数字的元组,并分析它们。我建议使用 imap_unordered 而不是 map,这样您就可以在数字可用时立即开始评估。

如果磁盘I/O出现问题,考虑使用SSD。

正如@RolandSmith & @selbie 所建议的那样,我通过用数据帧替换它并附加到它来避免 IO 连续写入 CSV 文件。我认为这消除了不一致之处。我按照 @CoMartel 的建议检查了 "feather""paraquet" 高性能 IO 模块,但我认为它用于将大文件压缩成较小的数据帧结构。附加选项不在那里。

观察:

  • 程序 运行 的第一个 运行 很慢。 连续的运行会更快。这种行为是一致的。
  • 我在程序完成后检查了一些尾随的 python 进程 运行ning 但没有找到。因此 CPU/RAM 中存在某种缓存,这使得连续 运行 的程序执行速度更快。

The program for 4000 input files took 72 sec for first-time execution and then an average of 14-15 sec for all successive runs after that.

  • 重新启动系统会清除这些缓存并导致程序在第一个 运行 时 运行 变慢。

  • 平均新鲜 运行 时间为 72 秒。但是程序一启动就被杀死,然后 运行ning 终止后的第一个干燥 运行 花费了 40 秒。所有连续 运行 秒后 14 秒的平均值。

  • 期间新鲜运行,所有核心利用率将围绕 10-13%。但是毕竟连续运行s,核心利用率就会100%

检查了1,20,000个文件,它遵循相同的模式。所以,现在,不一致已经解决了。因此,如果需要将此类代码用作服务器,则应为 CPU/RAM 创建一个干燥的 运行 以便在它可以开始接受 API 查询以获得更快的结果之前进行缓存。