`multiprocessing.Process` 正在修改他们不应该访问的非共享变量

`multiprocessing.Process` are modifying non-shared variables they should not have access to

进程正在改变它们不应该改变的东西。

一个Worker有一个状态变量(一个mp.Value)。此值设置为 -1,它(Worker)在循环中将其更改为 1

但是,似乎可以通过生成第二个 Worker 将该值 返回 重置为 -1,即使这与原来的一对。这好像应该是不可能的吧。

行为:

当第二个 Worker 启动时,第一个工人 (self.state.value ) 的状态将重置为 -1。这被捕获,我们打印出发现错误。

代码:

import multiprocessing as mp
import time


class Worker:
    def __init__(self, tag, service_state) -> None:
        self.tag = tag
        self.local_state = int(service_state.value)
        self.state = service_state
        self.run_work_loop()

    def run_work_loop(self) -> None:
        print(f"[{self.tag}] Running... {self.state.value} {self.local_state}")
        while True:
            if self.state.value != self.local_state:
                print(f"[{self.tag}] Illegal change. Shared state: {self.state.value} Local State: {self.local_state}")
                break

            elif self.state.value == -1:
                self.state.value = self.local_state = 1
                print(f"[{self.tag}] Set Shared State: {self.state.value} Local State: {self.local_state}.")


if __name__ == "__main__":
    mp.Process(target=Worker, args=("A", mp.Value('i', -1))).start()
    time.sleep(.03)
    mp.Process(target=Worker, args=("B", mp.Value('i', -1))).start()


输出:

[A] Running... -1 -1
[A] Set Shared State: 1 Local State: 1.
[A] Illegal change. Shared state: -1 Local State: 1
[B] Running... -1 -1
[B] Set Shared State: 1 Local State: 1.

问题是您正在创建 Value 立即超出父进程范围的实例,这使得它们被垃圾收集。因为 of the way Python allocates memory for multiprocessing.Value objects,第二个 Value 最终使用与第一个 Value 完全相同的共享内存位置,这意味着第二个最终踩在第一个上。您可以做一些实验来查看实际效果。例如,这不会打印警告:

if __name__ == "__main__":
    mp.Process(target=Worker, args=("A", mp.Value('i', -1))).start()
    time.sleep(.03)
    a = mp.Value('i', 1)
    mp.Process(target=Worker, args=("B", mp.Value('i', -1))).start()

我们分配给aValue被初始化为1,它覆盖了我们传递给进程“A”的匿名Value。因为我们用 1 覆盖它,所以不会打印非法状态消息。如果我们改为将其初始化为任何其他值,您将再次看到警告。这将打印一条关于 -2, 的非法状态消息,例如:

if __name__ == "__main__":
    mp.Process(target=Worker, args=("A", mp.Value('i', -1))).start()
    time.sleep(.03)
    a = mp.Value('i', -2)
    mp.Process(target=Worker, args=("B", mp.Value('i', -1))).start()

您的代码应该真正将您创建的 Value 实例保存为父进程中的局部变量,既可以避免此问题,也可以因为创建您实际不共享的共享值毫无意义。像这样:

if __name__ == "__main__":
    a = mp.Value('i', -1)
    mp.Process(target=Worker, args=("A", a)).start()
    time.sleep(.03)
    b = mp.Value('i', -1)
    mp.Process(target=Worker, args=("B", b)).start()