在 Python MutiProcessing 中分享 const global varible?

share const global varible in python mutiprocessing?

提问人:Alkaid C 提问时间:11/15/2023 最后编辑:Alkaid C 更新时间:11/15/2023 访问量:49

问:

基本上我想做的是:


def func1(a):
    return theBigStaticVar+a

a=[1,2,3...100]
pool = multiprocessing.Pool() 
theBigStaticVar=10
outputs = pool.map(func1, a) 

print(outputs)

pool.close()

这会给我一个错误NameError: name 'theBigStaticVar' is not defined

theBigStaticVar 表示一大块数据(在我的实际案例中约为 20MB),并且只会在 func1 中查看,而不会修改。因此,我认为它可以在不同的进程之间共享,而不必担心锁定或同步。如何有效地将此数据发送到 func1?

我唯一能想到的方法是

def func1(pair):
    return pair[0]+pair[1]

theBigStaticVar=10
pairs=[[1,theBigStaticVar],[2,theBigStaticVar ],[3,theBigStaticVar],...[100,theBigStaticVar]]
pool = multiprocessing.Pool() 
outputs = pool.map(func1, pairs) 

print(outputs)

pool.close()

但似乎它会复制 100 次。有没有更有效的方法?theBigStaticVar

并行 python 多处理

评论

0赞 Charles Duffy 11/15/2023
单独的进程意味着您拥有自己的内存空间。这意味着,如果你想让任何内容双向共享,你需要在进程之间执行某种显式的通信(而不是“在子项启动时从父项复制到子项一次”,这在分叉模型中是免费获得的)。这就是您不必处理 Python GIL 而获得性能增强的全部原因——如果必须通过锁定在进程之间协调对共享对象的访问,那么除了多线程本身之外,多处理还将存在与多线程相同的性能问题。
1赞 Charles Duffy 11/15/2023
(除此之外,多处理通常是正确的工具;我看到很多人试图在使软件性能变差而不是更好的情况下使用它;当然,需要更多地了解您的真实用例,才能知道您是否拥有其中之一)。
0赞 Mark Setchell 11/15/2023
你到底在你的大静态变量中存储了什么 - 它是一个图像吗?字典?您的多个流程究竟如何处理它?它们通常运行多长时间?

答:

1赞 LucasBR 11/15/2023 #1

主要问题是您在 .此外,use 用于调用该方法。您可以在此处查看有关原因的更多信息。Pool()if __name__ == "__main__"

请参阅下面的代码:

import multiprocessing

a=[1, 2, 3, 100]

def func1(x):
    return theBigStaticVar+x

theBigStaticVar=10

if __name__ == '__main__':
    with multiprocessing.Pool() as p:
        print(p.map(func1, a))

评论

0赞 Alkaid C 11/15/2023
明白了。你的方法有效,但它似乎比我的原生尝试还要慢。我注意到如果我们这样做,那么 hello 将被打印很多次。这是否意味着那里的代码被执行了多次?因为我不是从虚空得益;获取此数据也需要花费几秒钟的时间。theBigStaticVar=10 print("hello") if __name__ == '__main__': with multiprocessing.Pool() as p: print(p.map(func1, a))theBigStaticVar
1赞 CtrlZ 11/15/2023 #2

多处理。Pool 允许您指定初始值设定项函数,从而可以方便地将大块数据放入全局空间中。

下面是一个示例:

from multiprocessing import Pool

def ipp(v):
    global theBigDataVar
    theBigDataVar = v

def process(n):
    return theBigDataVar + n

def main():
    theBigDataVar = 10
    with Pool(initializer=ipp, initargs=(theBigDataVar,)) as pool:
        print(pool.map(process, range(1, 10)))

if __name__ == "__main__":
    main()

输出:

[11, 12, 13, 14, 15, 16, 17, 18, 19]

评论

0赞 Mark Setchell 11/15/2023
请问,这与之后将左对齐放在线上有什么不同?theBigDataVar = 10from multiprocessing import Pool
1赞 CtrlZ 11/16/2023
@MarkSetchell 在这种特殊情况下,没有什么不同,但我将其作为通用解决方案提供。在处理无法腌制的物体时,它就发挥了自己的作用。即使“共享”对象可以被酸洗,如果对象很大,这种技术也是有益的 - 即,酸洗开销被移除了
0赞 Mark Setchell 11/16/2023
很酷 - 感谢您抽出宝贵时间回答。