【问题标题】:Multiprocessing pool spawn initialization very slow, 100s for 16 processes多处理池生成初始化非常慢,16 个进程为 100 秒
【发布时间】:2021-04-15 08:01:41
【问题描述】:

在我的程序中,我需要生成 16 个多处理池,以在我的 3950x 上使用 16 个内核。我有一个初始化器,它在 spawn 子进程中初始化三个全局变量(总共大约 300kb)。

在使用初始化程序之前,每个进程大约需要 1 秒才能生成。现在 16 个过程总共需要大约 100 秒!知道为什么现在这么慢吗?示例代码如下:

def set_mp_global_vars(bc, bm, bf_n):
    """mp initialiser which sets global vars to reduce mp overhead"""
    global base_comps, base_matches, bf_names
    base_comps = bc
    base_matches = bm
    bf_names = bf_n

int_pool_workers = mp.cpu_count()
pool = mp.Pool(processes=int_pool_workers, initializer=set_mp_global_vars,
               initargs=(base_comps, base_matches, bf_names))

【问题讨论】:

  • 在进程之间传递数据涉及一方面进行酸洗,另一方面取消酸洗,以及一些磁盘 I/O,这可能是很多开销——尽管 100 倍确实看起来太多了……
  • 但这是我试图避免的,但设置全局变量,这样我就不需要在每次需要这些变量时腌制并将其传递给进程。假设我有 20,000 个进程,那么我只需为每个池初始化 16 次,而不是腌制 20,000 次。
  • 更新:看来是变量“bm”导致了缓慢。删除“bm”作为参数并将 base_matches 作为全局变量会导致 16 个进程在大约 16 秒内生成。 “bm”是约 8000 个自定义类实例的嵌套默认字典。 getsizeof 说它只有大约 300kb,但不确定这是否只是参考对象而不是真实大小。
  • 已经有一段时间了,但我记得读过 getsizeof() 的值不可靠。
  • getsizeof() 返回那个对象的大小。如果该对象是一个包含对其他对象的引用的容器,它只会递归地计算保存这些顶级引用的内存,而不是它们引用的对象的大小。例如L = [os.urandom(1<<30)] 创建一个包含对 1GB 缓冲区的引用的列表,但 sys.getsizeof(L) == 64

标签: python windows multiprocessing python-3.8


【解决方案1】:

在 Windows 10 上使用 Python 3.9.2 并在 Threadripper CPU 上生成 30 个进程需要 23 秒,同时开启 Pycharm 调试。如果我不调试就运行,需要0.21s。

pydev 调试器将 mp.Pool 减慢 100 倍。

你也可以看看:python-3-6-multiprocessing-pool-very-slow-to-start-using-windows

【讨论】:

    猜你喜欢
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 2022-01-08
    • 2020-12-13
    • 1970-01-01
    • 2011-02-24
    • 2011-10-27
    相关资源
    最近更新 更多