python - 为什么不同的 multiprocessing.Value 对象指向相同的值?

标签 python multiprocessing python-multiprocessing

在下面的程序中,创建了两个进程。每个接收它自己的 multiprocessing.Value 对象。不知何故,这两个过程仍然相互影响。为什么?

我预计这两个进程会死锁:第一个进程可以将计数器递增一次(最初为 0),但随后应该等待它再次变为偶数。第二个进程永远不能增加它,因为它最初是 0 并且永远不会改变。不知何故,这种死锁并没有发生,两个进程都继续运行。

import multiprocessing
import time


def inc_even(counter):
    print(f"inc_even started. {hash(counter)=}")
    while True:
        if counter.value % 2 == 0:
            counter.value += 1
            print("inc_even incremented counter")
        else:
            time.sleep(1)


def inc_odd(counter):
    print(f"inc_odd started. {hash(counter)=}")
    while True:
        if counter.value % 2 == 1:
            counter.value += 1
            print("inc_odd incremented counter")
        else:
            time.sleep(1)


multiprocessing.Process(
    target=inc_even,
    kwargs={
        "counter": multiprocessing.Value("i", 0),
    },
).start()
multiprocessing.Process(
    target=inc_odd,
    kwargs={
        "counter": multiprocessing.Value("i", 0),
    },
).start()

输出:

inc_even started. hash(counter)=8786024404161
inc_even incremented counter
inc_odd started. hash(counter)=8786024404157
inc_odd incremented counter
inc_even incremented counter
inc_odd incremented counter
...

有趣的是,如果我将其更改为首先创建两个保存两个计数器的变量,则会发生死锁:

counterA = multiprocessing.Value("i", 0)
counterB = multiprocessing.Value("i", 0)
multiprocessing.Process(
    target=inc_even,
    kwargs={
        "counter": counterA,
    },
).start()
multiprocessing.Process(
    target=inc_odd,
    kwargs={
        "counter": counterB,
    },
).start()

输出:

inc_even started. hash(counter)=8765172881357
inc_even incremented counter
inc_odd started. hash(counter)=8765172756097

编辑:如果我用某些自定义类替换 multiprocessing.Value 对象,则不会发生这种情况:

class CustomCounter:
    def __init__(self) -> None:
        self.value = 0
multiprocessing.Process(
    target=inc_even,
    kwargs={
        "counter": CustomCounter(),
    },
).start()
multiprocessing.Process(
    target=inc_odd,
    kwargs={
        "counter": CustomCounter(),
    },
).start()

这正如预期的那样陷入僵局。所以它一定是由 multiprocessing.Value 引起的,而不仅仅是一般的多处理。

最佳答案

第一个值在父进程中被回收,导致第二个值使用相同的共享内存进行分配。


根据文档,您的代码应该可以工作。下"Explicitly pass resources to child processes" ,文档说

Apart from making the code (potentially) compatible with Windows and the other start methods this also ensures that as long as the child process is still alive the object will not be garbage collected in the parent process. This might be important if some resource is freed when the object is garbage collected in the parent process.

不幸的是,文档与实现不匹配。实际执行explicitly deletes BaseProcess.start 内应该阻止您的值被回收的引用:

del self._target, self._args, self._kwargs

这意味着您的代码仅在您自己保存对 Value 实例的引用时才有效,就像您在使用 counterAcounterB 变量的版本中所做的那样。

文档和实现之间的不匹配可能应该在 CPython 上报告 issue tracker .

关于python - 为什么不同的 multiprocessing.Value 对象指向相同的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77269319/

相关文章:

python - 使用python多处理与函数共享信号量

python - 服务器上多个客户端的扭曲线程

python - 请求线程卡在Python中

python - 在 facebook 上发布,无需 api,但通过 http 请求

python - 将 tastypie 导入到项目中

python - PyLatex 基本脚本不会运行,因为找不到脚本解释器

Python:我的带有五个进程的 python 程序使用了多少个内核?

python - 在Python多处理模块中使用Pool和Queue

python - 多处理池示例不起作用并卡住内核

python - 如何在 __init__ 上创建 __len__ 函数?