Python多处理map_async挂起

时间:2012-03-18 17:18:12

标签: python multiprocessing pool

我在解析器中关闭一个进程池时遇到了一些麻烦[可能]。完成所有任务后,它会挂起并且什么也不做,cpu使用率约为1%。

profiles_pool = multiprocessing.Pool(processes=4)
pages_pool = multiprocessing.Pool(processes=4)

m = multiprocessing.Manager()
pages = m.list(['URL'])
pages_done = m.list()

while True:
    # grab all links
    res = pages_pool.imap_unordered(deco_process_people, pages, chunksize=1)

    pages_done += pages
    pages = []

    for new_users,new_pages in res:
        users.update(new_users)
        profile_tasks = [ (new_users[i]['link'],i) for i in new_users ]
        # enqueue grabbed links for parsing
        profiles_pool.map_async(deco_process_profiles, 
                                profile_tasks, chunksize=2, 
                                callback=profile_update_callback)
        # i dont need a result of map_async actually
        # callback will apply parsed data to users dict
        # users dict is an instance of Manager.dict()

        for p in new_pages:
            if p not in pages_done and p not in pages:
                pages.append(p)

    # we need more than 900 pages to be parsed for bug occurrence
    #if len(pages) == 0:
    if len(pages_done) > 900:
        break


# 
# closing other pools
#

# ---- the last printed string: 
print 'Closing profiles pool',
sys.stdout.flush()
profiles_pool.close()
profiles_pool.join()
print 'closed'

我猜问题是池队列中的错误打开任务计算,但我不是shure而且无法检查这个 - idk如何获取任务队列长度。

它可以是什么,在哪里先看?

2 个答案:

答案 0 :(得分:1)

最明显的问题是pages_done是一个同步的Manager.list对象(因此每个进程都可以原子方式访问它),但是当pages以这样的方式启动时,它很快就变成了普通的un(多)处理列表:

pages_done += pages
pages = []

第二个引用行将pages重新绑定到一个新的空普通列表。

即使你删除了第二行pages的所有元素(而不是重新绑定赋值),你也可能遇到一场比赛,其中(例如)pages有A,B和当你在第一行上做+=但在第二行中成为A,B,C和D时,C就在其中。

快速解决方法是逐项取消pages项,然后将它们一次放入pages_done个(效率不高)。最好不要让这些不是共享的数据结构;在引用的代码中它看起来不像它们(我假设一些不带引号的代码依赖于它 - 因为否则pages的重新绑定无论如何都是红鲱鱼!)。

答案 1 :(得分:1)

我发现了一个错误的原因:“如果pool.map的可迭代参数为空,则多处理池对象的连接方法会挂起”

http://bugs.python.org/issue12157