Python multiprocessing.Pool 和参数 pickling

标签 python multiprocessing pickle

考虑以下示例:

import multiprocessing as mp

def job(l):
    l.append(1)
    return l

if __name__ == "__main__":
    pool = mp.Pool(1)
    my_list = []
    out = pool.map(job, [my_list for i in range(5)])
    pool.close()
    pool.join()
    print(out)

调用 pool.map 时,我希望参数被 pickle,然后在调用作业后被 unpickled(因此每次都重新创建)。然而,观察到的输出是

[[1, 1], [1, 1], [1, 1], [1, 1], [1]]

有人可以解释一下这是怎么回事吗?我希望输出 是五个 [1] 或 [[1], [1, 1], ..., [1, 1, 1, 1, 1]] 的列表,两者都不是。

最佳答案

pool.mapchunksize 参数是您混淆的原因。显然,它会为您的设置选择自动设置 chunksize=2,因为您还可以通过显式设置 chunksize=2 获得您观察到的输出。

使用 chunksize=1 你会得到 [[1], [1], [1], [1], [1]] 使用 chunksize=3 你会得到 [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1], [ 1, 1]].

如果你用打印扩展你的代码,你可以观察会发生什么:

import multiprocessing as mp

def job(l):
    print(f'before append {l}')
    l.append(1)
    print(f'after append {l}')
    return l

if __name__ == "__main__":
    pool = mp.Pool(1)
    my_list = []
    out = pool.map(job, [my_list for _ in range(5)], chunksize=2)
    pool.close()
    pool.join()
    print(out)

这会给你这个输出:

before append []
after append [1]
before append [1]
after append [1, 1]
before append []
after append [1]
before append [1]
after append [1, 1]
before append []
after append [1]
[[1, 1], [1, 1], [1, 1], [1, 1], [1]]

Process finished with exit code 0

您可以看到,“before append”仅从空列表开始三次,而不是您预期的五次。这是因为对于 chunksize=2 和可迭代对象中的五个项目,您有 5/2 = 2.5 个任务。一半的任务是不可能的,所以这就是为什么你最终有 3 个任务:2 个任务有两个项目 block ,一个任务有一个项目 block 。

现在,对于前两个任务,您的函数 job 的第一次执行获取未经处理的空列表并附加 1。然后第二次执行获得与第一次执行刚刚修改的相同列表,因为您的项目只是对该任务中相同列表的引用。第二次执行也会改变第一次执行的结果,因为两者修改的是同一个底层对象。第二次执行后,任务完成,两次执行的结果 [[1, 1], [1, 1]] 被发送回父级。正如我们所说,这发生在前两个任务中。

第三个任务只有一次 job 的执行,并且它的结果没有被第二个任务修改,所以结果只有 [1]。

如果您在代码末尾添加 for obj in out: print(id(obj)),您将看到结果中的三个单独列表获得了三个不同的 ID,如下所示已经构建了许多任务来处理您的可迭代对象(CPython)。:

140584841382600
140584841382600
140584841383432
140584841383432
140584841383368

关于Python multiprocessing.Pool 和参数 pickling,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52487079/

相关文章:

python - 在 Python 中加载字典最有效的方法是什么?

python - 如何创建只有一个元素的 Python 集?

python - 在 python : child processes going defunct while others are not, 中不确定为什么

python - 用于多处理的共享内存中的大型 numpy 数组 : Is something wrong with this approach?

python - 在多个Python进程之间共享RabbitMQ channel

python - JSON 序列化对象在多处理调用时出错 - TypeError : XXX objects not callable error

python - 用python绘制关系矩阵

python - 检查 Pandas 中的一个系列是否是另一个系列的子集

python - 在 ubuntu 中嵌入 python 时出现段错误

python - 文件对象中的rb和r+b模式有什么区别