【问题标题】:Python Multiprocessing fast only after first runPython 多处理仅在第一次运行后快速
【发布时间】:2020-02-12 14:05:49
【问题描述】:

我有一个脚本,它使用多处理来打开约 200k .csv 文件并对其执行计算。这是工作流程:

1) 考虑一个包含约 200k .csv 文件的文件夹。每个 .csv 文件都包含以下内容:

.csv 文件示例:

0, 1
2, 3
4, 5
...
~500 rows

2) 脚本将所有 .csv 文件的列表保存在 list()

3) 由于我有 8 个处理器可用,该脚本将包含 ~200k .csv 文件的列表分成 8 个列表。

4) 脚本调用do_something_with_csv() 8 次并行计算。

在线性模式下,执行大约需要 4 分钟。

并行和串行,如果我第一次执行脚本,需要更长的时间。如果我执行第二次、第三次等时间,大约需要 1 分钟。似乎 python 正在缓存某种类型的 IO 操作?看起来是因为我有一个进度条,例如,如果我执行到进度条为 5k/200k 并终止程序,下一次执行将非常快地经过前 5k 次运行,然后变慢。

Python 版本:3.6.1

伪 Python 代码:

def multiproc_dispatch():
        lst_of_all_csv_files = get_list_of_files('/path_to_csv_files')
        divided_lst_of_all_csv_files = split_list_chunks(lst_of_all_csv_files, 8)

        manager = Manager()
        shared_dict = manager.dict()

        jobs = []
        for lst_of_all_csv_files in divided_lst_of_all_csv_files:
            p = Process(target=do_something_with_csv, args=(shared_dict, lst_of_all_csv_files))
            jobs.append(p)
            p.start()

        # Wait for the worker to finish
        for job in jobs:
            job.join()

def read_csv_file(csv_file):
    lst_a = []
    lst_b = []
    with open(csv_file, 'r') as f_read:
        csv_reader = csv.reader(f_read, delimiter = ',')
        for row in csv_reader:
            lst_a.append(float(row[0]))
            lst_b.append(float(row[1]))
    return lst_a, lst_b


def do_something_with_csv(shared_dict, lst_of_all_csv_files):
    temp_dict = lambda: defaultdict(self.mydict)()
    for csv_file in lst_of_all_csv_files:
        lst_a, lst_b = read_csv_file(csv_file)
        temp_dict[csv_file] = (lst_a, lst_b)

    shared_dict.update(temp_dict)


if __name__ == '__main__':
    multiproc_dispatch()

【问题讨论】:

  • 两个连续的线性运行是否都在 4 分钟左右?
  • 我刚刚进行了比较,实际上在第二次运行线性模式后不到 4 分钟。你知道为什么吗?我终止了脚本,它不在同一次执行的循环中。
  • 在下面查看我的答案

标签: python python-3.x python-multiprocessing


【解决方案1】:

这无疑是 RAM 缓存开始发挥作用,这意味着第二次加载文件会更快,因为数据已经在 RAM 中并且不是来自磁盘。 (努力在这里找到好的参考资料,欢迎任何帮助) 这与多处理无关,甚至与 python 本身无关。

自问题编辑后无关我认为并行运行时代码所花费的持续时间较长的原因来自您在每个子进程中访问的 shared_dict 变量(参见例如 here )。在 python 中的进程之间创建和发送数据很慢,应该减少到最低限度(在这里你可以为每个作业返回一个 dict 然后合并它们)。

【讨论】:

  • 我的共享字典已经在执行您在原始代码中提出的建议。也就是说,共享字典只更新了 8 次。我会更新问题。我不明白如果我终止程序,对象怎么会在 RAM 上。我认为这可能与垃圾收集有关。
  • 你的听写好了。垃圾收集意味着您的 RAM 可以被其他程序免费使用;但是操作系统不会“重置”它;如果您在不久之后重新加载相同的文件,它仍然会在缓存中。这在 python 中当然是不可见的,但在操作系统级别上是不可见的。这就是为什么 ram 监控工具有一个“缓存”类别的原因。阅读有关 RAM 缓存的更多信息!
  • 我明白,但我觉得很奇怪的是我正在监控 RAM 使用情况,如果所有 200k 文件都被缓存,它并没有增加。我什至用 5M .csv 文件进行了测试,第二次运行后执行速度更快,并且 RAM 使用率始终相同。
  • 缓存的 RAM 被认为是空闲的 RAM;通常,几乎所有空闲 RAM 都用作先前计算的缓存(不仅来自 python)。因此,也许您的新缓存只是删除了一些旧缓存(前提是您确实查看了 Cached ram 而不是 free ram)
  • 现在,这更有意义了。谢谢。
猜你喜欢
  • 2012-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多