使用多进程池出现意外行为

5
在下面的代码中,我期望输出结果是2,因为我在将函数分配给多进程池之前更改了config的值,但实际上我得到了5。我确定有一个很好的理由,但不确定如何解释。
from multiprocessing import Pool 
config = 5

class Test:

  def __init__(self):
    print("This is init")

  @classmethod
  def testPrint(cls, data):
    print(config)
    print("This is testPrint")
    return config

if __name__ == "__main__" :
  pool = Pool()
  config = 2
  output = pool.map(Test.testPrint, range(10))
  print(output)

输出

5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]

我不确切地知道这里到底发生了什么,但我们使用了一些多进程技术,并学会了避免使用全局变量。由于没有共享内存环境,在某个时刻通过 Pickling 复制环境。对于这个特定的值,我无法确定正在发生什么。我要补充的是建议我们所学到的...非常明确地传递所有共享的值,无论是在子进程内部还是在外部。 - CryptoFool
听起来@tdelaney的答案与此类似,只是更详细。一切都好。 - CryptoFool
@Steve 我本来以为在子进程中写入共享值会出问题,但没想到读取也会。今天又学到了一件新事。 - vibhud
1个回答

5

在创建池时会创建新的进程。然后,对于父进程内存空间所做的更改(除了通过池函数传递的内容,如.map),子进程看不到。像linux这样的分叉系统会针对父进程内存空间创建写时复制视图 - 写操作会为父进程创建独立的内存块,子进程看不到。生成系统会重新导入模块(设置全局变量),然后尝试pickle / unpickle子进程的状态。在这两种情况下,在Pool类初始化返回到您的程序之前完成此操作。


1
感谢您的解释,我在创建池之前更改了配置值进行验证。它确实打印出了所需的结果。 - vibhud

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接