为什么它会抛出"'模块'对象没有属性XXX"从multiprocessing.Pool调用apply_async时出错?

时间:2014-08-28 14:13:51

标签: python multiprocessing

代码如下。当我将其复制并粘贴到我的cmd提示符中时,它会抛出'module'对象没有属性'func',但当我将其保存为 .py 文件时并执行python test.py,它只是工作正常。

import multiprocessing
import time

def func(msg):
    for i in xrange(3):
        print msg
        time.sleep(1)



if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=4)
    for i in xrange(5):
        msg = "hello %d" %(i)
        pool.apply_async(func, (msg, ))
    pool.close()
    pool.join()
    print "Sub-process(es) done."

在运行python代码时,有没有人能给我一个关于提示符和文件之间区别的解释?非常感谢!

1 个答案:

答案 0 :(得分:6)

这种情况正在发生,因为在Windows上,func需要被腌制并通过IPC发送到子进程。为了让孩子解开func,它需要能够从父的__main__模块中导入它。当在普通Python脚本中发生这种情况时,子进程可以重新导入您的脚本,__main__将包含在脚本顶层声明的所有函数,因此它可以正常工作。但是,在交互式解释器中,您在解释器中定义的函数不能简单地从正常脚本中的文件中重新导入,因此它们位于{{1}在孩子身上。如果您直接使用__main__重新创建问题,则会更清楚:

multiprocessing.Process

这样,>>> def f(): ... print "HI" ... >>> import multiprocessing >>> p = multiprocessing.Process(target=f) >>> p.start() >>> Traceback (most recent call last): File "<string>", line 1, in <module> File "C:\python27\lib\multiprocessing\forking.py", line 381, in main self = load(from_parent) File "C:\python27\lib\pickle.py", line 1378, in load return Unpickler(file).load() File "C:\python27\lib\pickle.py", line 858, in load dispatch[key](self) File "C:\python27\lib\pickle.py", line 1090, in load_global klass = self.find_class(module, name) File "C:\python27\lib\pickle.py", line 1126, in find_class klass = getattr(mod, name) AttributeError: 'module' object has no attribute 'f' 无法找到模块就更清楚了。如果您向pickle添加一些跟踪,则可以看到pickle.py指的是'module'

__main__

再次使用额外的print语句重新运行相同的代码会产生以下结果:

def load_global(self):
    module = self.readline()[:-1]
    name = self.readline()[:-1]
    print("module {} name {}".format(module, name))  # I added this.
    klass = self.find_class(module, name)
    self.append(klass)

值得注意的是,此示例在Posix平台上实际上运行正常,因为module multiprocessing.process name Process module __main__ name f < same traceback as before> 用于生成子进程,这意味着在创建os.fork()之前定义的任何函数都将在孩子的Pool模块。因此,虽然上面的示例可行,但是这个仍然会失败,因为在创建__main__之后定义了worker函数(这意味着在调用Pool之后):< / p>

os.fork()