【问题标题】:Python multiprocessing >= 125 list never finishesPython 多处理 >= 125 列表永远不会完成
【发布时间】:2013-09-28 20:50:16
【问题描述】:

我正在尝试实现这个多处理 tutorial 用于我自己的目的。起初我认为它不能很好地扩展,但是当我做了一个可重现的例子时,我发现如果项目列表超过 124,它似乎永远不会返回答案。在 x = 124 它运行在 0.4 秒,但是当我将它设置为 x = 125 它永远不会完成。我在 Windows 7 上运行 Python 2.7。

from multiprocessing import Lock, Process, Queue, current_process
import time

class Testclass(object):
    def __init__(self, x):
        self.x = x

def toyfunction(testclass):
    testclass.product = testclass.x * testclass.x
    return testclass


def worker(work_queue, done_queue):
    try:
        for testclass in iter(work_queue.get, 'STOP'):
            print(testclass.counter)
            newtestclass = toyfunction(testclass)
            done_queue.put(newtestclass)

    except:
        print('error')

    return True

def main(x):

    counter = 1

    database = []
    while counter <= x:
        database.append(Testclass(10))
        counter += 1
        print(counter)



    workers = 8
    work_queue = Queue()
    done_queue = Queue()
    processes = []

    start = time.clock()
    counter = 1

    for testclass in database:
        testclass.counter = counter
        work_queue.put(testclass)
        counter += 1
        print(counter)


    print('items loaded')
    for w in range(workers):
        p = Process(target=worker, args=(work_queue, done_queue))
        p.start()
        processes.append(p)
        work_queue.put('STOP')

    for p in processes:
        p.join()

    done_queue.put('STOP')

    newdatabase = []
    for testclass in iter(done_queue.get, 'STOP'):
        newdatabase.append(testclass)

    print(time.clock()-start)
    print("Done")
    return(newdatabase)

if __name__ == '__main__':
    database = main(124)
    database2 = main(125)

【问题讨论】:

  • 他在这里发布了另一个对我有用的问题。 stackoverflow.com/questions/19070638/…
  • 我在另一篇文章中解决了这个问题。我已经尝试在我的两台计算机上运行上面的代码,并且当x=125 并且从不打印完成时,它在两台计算机上都挂起。
  • 在 125 处,我也不会停下来。 Windows Vista 上的 Python 2.7.5。它似乎永远在等待.join() 其中一个进程。建议您尝试将其缩减为最小的失败案例,然后open a bug report。在 Python 3.3.2 下也无法终止。
  • 有趣的是,即使 workers 设置为 1,它也无法停止。似乎进程不会停止“因为”done_queue 尚未停止耗尽。如果我将worker() 更改为最后执行done_queue.put('STOP'),并更改main 以取消该行,而不是调用done_queue.get() 直到'STOP' 被看到workers 次,那么此代码即使对于一百万个项目。

标签: python multiprocessing


【解决方案1】:

好的!来自the docs

警告如上所述,如果子进程已将项目放入队列中(并且它没有 使用 JoinableQueue.cancel_join_thread),那么该进程将不会终止,直到所有 缓冲的项目已被刷新到管道。 这意味着如果您尝试加入该进程,除非您确定,否则您可能会遇到死锁 已放入队列的所有项目都已被消耗。同样,如果 子进程是非守护进程,然后父进程可能会在尝试退出时挂起 加入其所有非恶魔的孩子。请注意,使用管理器创建的队列确实 没有这个问题。请参阅编程指南。

正如我在之前的评论中指出的,代码尝试在.join() 处理之前 done_queue 队列被耗尽 - 并且在以一种时髦的方式更改代码以确保@987654324 @ 在.join()'ing 之前被耗尽,代码对一百万个项目运行良好。

所以这是一个飞行员错误的例子,虽然很模糊。至于为什么行为取决于传递给main(x) 的数字,这是不可预测的:这取决于内部缓冲的方式。真有趣;-)

【讨论】:

  • 您对上面的代码有什么特别的建议吗?有没有其他方法可以让人们从队列中取回成品?
  • 我已经在评论中解释了我是如何“解决”这个问题的:在它结束之前将 worker() 更改为 done_queue.put('STOP')。将主程序的迭代更改为 done_queue 以计算它看到 'STOP' 的次数 - 当它看到 workers 时就完成了。移动.join()s 之后done_queue上的迭代完成。
猜你喜欢
  • 1970-01-01
  • 2018-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
  • 1970-01-01
  • 2017-01-27
相关资源
最近更新 更多