`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()
我们分配给a
的Value
被初始化为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()
进程正在改变它们不应该改变的东西。
一个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()
我们分配给a
的Value
被初始化为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()