生成过程中的静态变量未初始化

Posted

技术标签:

【中文标题】生成过程中的静态变量未初始化【英文标题】:Static variables in spawn processes are not initialised 【发布时间】:2021-07-07 21:41:07 【问题描述】:

对我来说很奇怪,“spawn”过程不会复制类的静态变量,但是使用“fork”一切都可以。

代码:

import typing as t
import multiprocessing as mp
from concurrent.futures import ProcessPoolExecutor


class Foo:
    static_var: int

    def __init__(self):
        pass


def func(foo_class: t.Type[Foo]):
    return foo_class.static_var


if __name__ == "__main__":
    # with ProcessPoolExecutor(mp_context=mp.get_context("fork")) as executor:
    with ProcessPoolExecutor(mp_context=mp.get_context("spawn")) as executor:
        foo_class = Foo
        foo_class.static_var = 10
        res = executor.map(func, [foo_class, foo_class])
        print(list(res))
    print('Done')

输出“分叉”:

[10, 10]
Done

输出“spawn”:

AttributeError: type object 'Foo' has no attribute 'static_var'

Python 版本:3.8.5

我不知道如何通过 spawn 来克服它(而且我不完全理解为什么它不起作用)。生成过程再次启动自己的解释器和导入模块(和类?),这就是为什么没有初始化静态变量? 如何通过类传递变量?

【问题讨论】:

【参考方案1】:

在多处理中,spwanfork-server 工作进程是新的 python 进程。 所有内存状态都是新鲜的,if __name__ == "__main__:" 块没有被执行。 这个意义上的静态类变量不是静态的。

fork工作进程中,整个进程内存被复制,因此类变量很可能被复制,但一个进程中的任何更改都不会影响其他进程。

两种可能的解决方案:

修改任务函数和参数,使任务是独立的,不依赖于非静态环境。 使用ProcessPoolExecutor 中的initializer 参数正确设置静态变量。
def worker_initializer():
    foo_class = Foo
    foo_class.static_var = 10

with ProcessPoolExecutor(
    initializer=worker_initializer,
    mp_context=mp.get_context("spawn")
) as executor:
    pass

【讨论】:

以上是关于生成过程中的静态变量未初始化的主要内容,如果未能解决你的问题,请参考以下文章

java中的全局变量和静态变量是在编译时分配内存还是在加载时分配内存??

静态区堆栈

类的加载过程和对象的创建

java中的静态变量,静态方法与静态代码块详解

全局变量和局部变量

内存的使用:栈区堆区静态区只读区