Python 多进程 - 全局列表中的共享计数器未正确递增

1 投票
1 回答
1119 浏览
提问于 2025-04-18 10:07

我正在尝试在多进程中实现一个共享计数器。我使用一个全局变量来避免序列化的问题。但我不明白的是,增加计数的操作似乎没有作用在我的全局计数器列表上(值总是0)。我猜代码可能在使用一个局部变量的实例,而这个实例最后被丢弃了。

我以为全局列表是可以修改的,因为它们是可变的。我还尝试明确地定义 global list_global 来说明我想使用这个变量的全局定义。

有人能指出我哪里出错了吗?

from multiprocessing import Pool, Value, Lock

list_global = [] # global variable to hold Counter values


#http://eli.thegreenplace.net/2012/01/04/shared-counter-with-pythons-multiprocessing/
class Counter(object):    
    def __init__(self, initval=0):
        self.val = Value('i', initval)
        self.lock = Lock()
##        self.val = initval

    def increment(self):
        with self.lock:
            self.val.value += 1

    def value(self):
        with self.lock:
            return self.val.value


def process_item(x):
    global list_global
    list_global[0].increment()     # increments
    return list_global[0].value()  # correctly returns incremented value


def main():
    global list_global

    print 'before', list_global[0].value()

    pool = Pool()
    print pool.map(process_item, range(10))
    pool.close()
    pool.join()

    #increments in process_item are not persistent
    #(do not appear to be modifying the global variable)
    print 'after', list_global[0].value()  #=> 0


# list_global holds 3 Counter objects
for i in range(3):
    list_global.append(Counter(0))


if __name__ == '__main__':
    global list_global
    main()
    #print list_global # list_global holds "Counter" objects
    for i in list_global:
        print i.value(), #=>[0,0,0] # expected [10,0,0]

1 个回答

2

更具体地说,你的问题在于你对多进程的理解有误,这导致你对输出结果的期望不正确。你不能声明一个全局变量然后在多个进程之间共享它。使用线程时情况会稍微好一些,但要理解你遇到的问题,首先需要明白多进程到底在做什么。

Pool.map() 启动你的子进程时,每个子进程都会启动一个 自己的 Python 解释器,并在其中导入你的顶层函数 process_item。这个独立的解释器实例也会创建 它自己的 list_global 实例。这个过程会在 每个 子进程中发生。你对 global 的调用并不会神奇地让这些独立运行的进程共享你模块中定义的列表。

撰写回答