【问题标题】:multiple output returned from python multiprocessing function从 python 多处理函数返回的多个输出
【发布时间】:2013-01-29 12:34:25
【问题描述】:

我正在尝试使用多处理来返回一个列表,但我不是等到所有进程都完成,而是从 mp_factorizer 中的一个返回语句中获得多个返回,如下所示:

None
None
(returns list)

在这个例子中,我使用了 2 个线程。如果我使用 5 个线程,则在列出列表之前将有 5 个 None 返回。这是代码:

def mp_factorizer(nums, nprocs, objecttouse):
    if __name__ == '__main__':
        out_q = multiprocessing.Queue()
        chunksize = int(math.ceil(len(nums) / float(nprocs)))
        procs = []
        for i in range(nprocs):
            p = multiprocessing.Process(
                    target=worker,                   
                    args=(nums[chunksize * i:chunksize * (i + 1)],
                          out_q,
                    objecttouse))
            procs.append(p)
            p.start()

        # Collect all results into a single result dict. We know how many dicts
        # with results to expect.
        resultlist = []
        for i in range(nprocs):
            temp=out_q.get()
            index =0
            for i in temp:
                resultlist.append(temp[index][0][0:])
                index +=1

        # Wait for all worker processes to finish
        for p in procs:
            p.join()
            resultlist2 = [x for x in resultlist if x != []]
        return resultlist2

def worker(nums, out_q, objecttouse):
    """ The worker function, invoked in a process. 'nums' is a
        list of numbers to factor. The results are placed in
        a dictionary that's pushed to a queue.
    """
    outlist = []
    for n in nums:        
        outputlist=objecttouse.getevents(n)
        if outputlist:
            outlist.append(outputlist)   
    out_q.put(outlist)

mp_factorizer 获取项目列表、线程数和工作人员应该使用的对象,然后拆分项目列表,以便所有线程获得相同数量的列表,并启动工作人员。 然后工作人员使用该对象从给定列表中计算某些内容,并将结果添加到队列中。 Mp_factorizer 应该从队列中收集所有结果,将它们合并到一个大列表中并返回该列表。但是 - 我得到了多个回报。

我做错了什么?还是由于 Windows 处理多处理的奇怪方式导致了这种预期的行为? (Python 2.7.3, Windows7 64bit)

编辑: 问题是if __name__ == '__main__': 的位置错误。我在处理另一个问题时发现,请参阅using multiprocessing in a sub process 以获取完整说明。

【问题讨论】:

  • 您所说的“我从一份退货声明中获得多份退货”是什么意思?另外,请发布一个可运行的示例。
  • 我将发布一个示例,但需要一段时间才能确保该示例能够重现问题。多次返回的意思是,如果我写 print mp_factorizer(list, 2, someobject),我不会让 print 命令执行一次,而是一次加上我设置线程数的次数,即 2 个线程:None None (prints list)(每个都在一个新行中)打印应该只执行一次。但我会得到 3 份打印输出。所以实际上 return 语句将在每次工作人员完成时执行(?),最后,当列表返回时。

标签: python windows-7 multiprocessing


【解决方案1】:

if __name__ == '__main__' 放错地方了。一个快速的解决方法是只保护对 mp_factorizer 的调用,就像 Janne Karila 建议的那样:

if __name__ == '__main__':
    print mp_factorizer(list, 2, someobject)

但是,在 Windows 上,主文件将在执行时执行一次 + 每个工作线程执行一次,在这种情况下为 2。所以这将是主线程的总共 3 次执行,不包括代码的受保护部分。

一旦在同一个主线程中进行其他计算,这可能会导致问题,并且至少会不必要地降低性能。即使只需要执行几次工作函数,在 Windows 中,所有不受 if __name__ == '__main__' 保护的东西都会被执行。

所以解决方案是保护整个主进程,只在之后执行所有代码 if __name__ == '__main__'.

如果worker函数在同一个文件中,但是,它需要从这个if语句中排除,否则它不能被多次调用以进行多处理。

伪代码主线程:

# Import stuff
if __name__ == '__main__':
    #execute whatever you want, it will only be executed 
    #as often as you intend it to
    #execute the function that starts multiprocessing, 
    #in this case mp_factorizer()
    #there is no worker function code here, it's in another file.

即使整个主进程都受到保护,worker函数仍然可以启动,只要它在另一个文件中。

伪代码主线程,带worker函数:

# Import stuff
#If the worker code is in the main thread, exclude it from the if statement:
def worker():
    #worker code
if __name__ == '__main__':
    #execute whatever you want, it will only be executed 
    #as often as you intend it to
    #execute the function that starts multiprocessing, 
    #in this case mp_factorizer()
#All code outside of the if statement will be executed multiple times
#depending on the # of assigned worker threads.

有关可运行代码的详细说明,请参阅using multiprocessing in a sub process

【讨论】:

    【解决方案2】:

    您的if __name__ == '__main__' 声明放错了位置。将它放在print 语句周围,以防止子进程执行该行:

    if __name__ == '__main__':
        print mp_factorizer(list, 2, someobject)
    

    现在你在mp_factorizer 内有了if,这使得函数在子进程内调用时返回None

    【讨论】:

    • 没错。我也是昨天才发现的。但是,仅保护调用 mp_factorizer 的部分并不是一个好主意,因为 python 将执行主进程中不受if __name__ == '__main__' 保护的所有代码,其次数与正在启动的线程一样多,在这种情况下为 2 次太频繁。详情见我的回答。
    • @harbun 我不会太担心执行一个额外的函数定义。但原则上你是正确的,一个真正的应用程序可以做一些你可能希望在子进程中避免的繁重初始化。
    猜你喜欢
    • 2019-02-07
    • 2021-07-19
    • 2021-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    相关资源
    最近更新 更多