多进程池初始化器无法进行pickle序列化

5

我正在尝试使用 multiprocessing.Pool 实现多线程应用程序。为了共享一些变量,我正在使用一个 Queue,如此处所示(链接)

def get_prediction(data):
    #here the real calculation will be performed
    ....


def mainFunction():
    def get_prediction_init(q):
        print("a")
        get_prediction.q = q

    queue = Queue()
    pool = Pool(processes=16, initializer=get_prediction_init, initargs=[queue,])

if __name__== '__main__':
    mainFunction()

这段代码在Debian机器上完美运行,但在另一台Windows 10设备上根本无法工作。它会出现错误

AttributeError: Can't pickle local object 'mainFunction.<locals>.get_prediction_init'

我并不确定是什么导致了这个错误。我应该如何解决这个问题,以便能在Windows设备上运行代码?
编辑:如果我在与mainFunction相同的层次上创建get_predediction_init函数,则问题得到解决。当我将其定义为内部函数时,它才会失败。对于我帖子中的混淆表示抱歉。

我在 mainFunction..get_prediction_init 上看到了2个点。 - Pedro Lobito
不确定这是否是问题的原因,但在Windows中,multiprocessing代码应该由if __name__ == '__main__':保护。 - roganjosh
抱歉!我添加了更多的代码来说明我的问题。 - zimmerrol
请发布一个完整的可执行程序,就像我为您所做的那样。当我猜测您编辑后代码中缺失的部分时,它在Windows上仍然可以正常工作。 - Tim Peters
@TimPeters 可以确认至少在 Windows 7 上发布的代码中存在错误。您提供的最小示例可以正常工作,但发布的代码会抛出 PicklingError 异常。 - roganjosh
@TimPeters 对不起(再次)。我在第一次编辑中复制和粘贴代码时犯了错误。 - zimmerrol
1个回答

3
问题出在你没有向我们展示的某个地方。例如,在你展示的AttributeError消息中,“mainFunction”是从哪里来的,这是一个谜。
以下是基于你发布的片段的完整可执行程序。我刚在Windows 10下使用Python 3.6.1运行了它,一切正常,打印了16次“a”。(我猜你正在使用Python 3,因为你的print语法)
import multiprocessing as mp

def get_prediction(data):
    #here the real calculation will be performed
    pass

def get_prediction_init(q):
    print("a")
    get_prediction.q = q

if __name__ == "__main__":
    queue = mp.Queue()
    pool = mp.Pool(processes=16, initializer=get_prediction_init, initargs=[queue,])
    pool.close()
    pool.join()

编辑

根据您的编辑,对于我来说,这个程序也很好用:

import multiprocessing as mp

def get_prediction(data):
    #here the real calculation will be performed
    pass

def get_prediction_init(q):
    print("a")
    get_prediction.q = q

def mainFunction():
    queue = mp.Queue()
    pool = mp.Pool(processes=16, initializer=get_prediction_init, initargs=[queue,])
    pool.close()
    pool.join()

if __name__ == "__main__":
    mainFunction()

编辑2

现在您已经将get_prediction_init()的定义移动到mainFunction的代码块内。现在我可以看到您的错误了 :-)

建议将函数定义放在模块级别,避免尝试对局部函数对象进行pickle。这可能会成为一场噩梦。也许有人想和它斗争,但不包括我 ;-)


我编辑了帖子并添加了有关mainFunction的更多信息。 - zimmerrol
好的!你知道为什么它在Windows上失败但在Debian上工作吗? - zimmerrol
回答这个问题就像是在“与之战斗”;-) 我甚至不想尝试。真正的答案往往会深入细节,最终你还是得将函数设为全局的。 - Tim Peters
1
但我会给出简短的课程:在Debian上,“Pool”通过“fork()”创建工作进程 - pickle与此无关。 在Windows上,“fork()”不可用,必须对对象进行pickling以便工作进程能够unpickle。 在Debian上,它们只是从父进程继承而来。 - Tim Peters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接