在Python 3中创建多处理池时,我很难找到将哪些对象和变量复制到子进程的答案。
换句话说,假设我有一个巨大的列表(~230000000个元素)存储在一个类中,该类实现了一个使用四个子进程池的函数。然后将此列表复制到所有四个子进程中,如果。
发布于 2022-07-21 10:28:48
Note:这个答案是部分的,因为我也找不到关于这方面的书面证据和文档,但如果你愿意的话,下面给出一些经验性的数据。
下面的代码用于演示如何使用Pool将数据传递/复制到子进程(实际列表l在map中不用于允许干净的打印):
from multiprocessing import Pool
import os
def process(x):
print(os.getpid(), __name__, 'l' in globals())
# A - l = list(range(100000))
if __name__ == "__main__":
# B - l = list(range(100000))
with Pool() as pool:
pool.map(process, [1,2,3,4])
print(os.getpid(), __name__, 'l' in globals())在Windows上
当取消注释A时,打印输出类似于:
19604 __mp_main__ True
6392 __mp_main__ True
19604 __mp_main__ True
7048 __mp_main__ True
6568 __main__ True将被给予。这是因为列表是在之外定义的-- __name__保护,而作为Windows中的进程--基本上是py文件--它们都定义了自己的l版本。
当取消注释B时,打印输出类似于:
7248 __mp_main__ False
22644 __mp_main__ False
22676 __mp_main__ False
16520 __mp_main__ False
19736 __main__ True将被给予。也就是说,由于列表是在__name__保护中定义的,只有__main__进程才定义了它,并且它将参数通过map传递给不同的进程。
在Linux上
取消对任何评论的注释将提供类似于以下内容的打印输出:
25261 __main__ True
25262 __main__ True
25263 __main__ True
25264 __main__ True
25260 __main__ True我猜想这是因为Linux使用fork来创建生成的进程,其中进程被“克隆”,因此列表将被定义为任意一种方式。
发布于 2022-07-21 14:56:50
具体地回答原来的问题,特别是关于“产卵”的用法(正如OP所提到的,他们熟悉“叉子”)
当创建流程对象时,它是用main构造的,然后使用命令行args执行一个新的process,以共享一对用于通信的文件句柄以及一个代码存根。
“引导”代码将尝试对主文件进行import,这就是为什么您需要对导入的意外副作用(if __name__ == "__main__":)进行保护,以及为什么在该保护之外的任何内容对子文件都是“可用的”。这主要是为了确保主文件中的函数是定义的,但是在模块级别上定义的任何变量也都是定义的。这对于常量非常有用,只要您有效地重新计算值并为每个进程创建一个副本并不重要。对于大型数据集,这是非常低效率的。
引导代码还将读取其中一个文件句柄,并尝试unpickle父程序发送给它的进程对象。流程的目标通常是您定义的函数,但是必须注意在导入的"main“命名空间中可以访问它(没有lambda,没有实例方法等等)。Python不使用泡菜序列化代码对象,而是传递如何正确导入函数,该函数与导入中没有具体命名空间的对象(侧栏,第三方multiprocess库试图通过使用dill而不是pickle来解决这个问题以获得普遍的成功)有风险。在子类Process类并将其他数据附加到流程实例时,也会考虑到这一点;这些数据都必须是可选择的。
一旦进程对象未被子进程成功地选中,就会调用run方法。这通常是代码的切入点。对于Pool,有一个大型类驻留在主进程上,并启动带有预定义函数的"worker“进程,该函数接收”作业“并返回结果,直到被告知退出为止。数据(由要执行的函数和该功能的args组成的任务项)通过Queue发送到和从工作人员那里发送,这与发送原始Process对象几乎一样:您放入队列中的东西被腌制、通过文件句柄发送,并且在子队列中没有被腌制。
https://stackoverflow.com/questions/73064110
复制相似问题