使用全局变量来跟踪多处理程序的进度

时间:2018-05-08 14:53:54

标签: python multiprocessing counter

我有一个程序,我在多处理中运行。我想要一个带打印的进度系统。

这就是我提出的:

import multiprocessing as mp
import os

global counter
global size

def f(x):
    global counter
    global size
    print ("{} / {}".format(counter, size))
    counter += 1
    return x**2

size = 4
counter = 1

result = list()
for x in [1,2,3,4]:
    result.append(f(x))

这个有效。但是,如果用以下内容替换底部:

with mp.Pool(processes = 2) as p:
    p.starmap(f, [1,2,3,4])

没有。我不明白为什么,任何人都可以帮忙搞定并运行吗?谢谢:))

N.B:这当然是一个虚拟的例子。

编辑:

您的解决方案会出现新问题。我会举个例子:

fix1 = 1
fix2 = 2
dynamic = [1,2,3,4,5]

def f(x, y, z):
    return x**2 + y + z

size = len(dynamic)
counter = 1

with mp.Pool(processes = 2) as p:
    for output in p.starmap(f, [(x, fix1, fix2) for x in dynamic]):
        print ("{} / {}".format(counter, size))
        counter += 1

这个有效,但最后完成所有印刷。

with mp.Pool(processes = 2) as p:
    for output in p.imap_unordered(f, [(x, fix1, fix2) for x in dynamic]):
        print ("{} / {}".format(counter, size))
        counter += 1

这个不起作用,并说f()缺少2个必需的位置参数fix1和fix2。

我知道为什么会出现这种行为?

N.B:我在Windows上运行。

1 个答案:

答案 0 :(得分:2)

在像linux这样的分叉系统中,子进程共享父内存空间的写时复制视图。如果一方更新内存,它将获得自己的已更改页面的私有副本。在其他系统上,创建一个新进程并执行一个新的python。在任何一种情况下,任何一方都不会看到其他人所做的改变这意味着每个人都在更新自己的count私人副本,而不会看到其他人的补充。

为了使事情变得复杂,stdout未同步。如果工人打印,你很可能会收到乱码。

另一种方法是在结果返回父池时对结果进行计数。父级跟踪计数,父级是唯一一次打印。如果您不关心返回数据的顺序,那么imap_unordered将很适合您。

import multiprocessing as mp

def f(x):
    return x**2

data = [1,2,3,4]
result = []

with mp.Pool(processes = 2) as p:
    for val in p.imap_unordered(f, data):
        result.append(val)
        print("progress",  len(result)/len(data))