多处理后,我的队列为空。进程实例完成

时间:2014-10-16 23:58:56

标签: python queue multiprocessing celery concurrent.futures

我有一个python脚本,位于文件顶部:

result_queue = Queue.Queue()
key_list = *a large list of small items* #(actually from bucket.list() via boto)

我了解到队列是过程安全的数据结构。我有一个方法:

def enqueue_tasks(keys):
    for key in keys:
        try:
            result = perform_scan.delay(key)
            result_queue.put(result)
        except:
           print "failed"

这里的perform_scan.delay()功能实际上叫芹菜工人,但我认为不相关(这是异步过程调用)。

我也有:

def grouper(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

最后我有一个main()功能:

def main():

    executor = concurrent.futures.ProcessPoolExecutor(10)
    futures = [executor.submit(enqueue_tasks, group) for group in grouper(key_list, 40)]
    concurrent.futures.wait(futures)
    print len(result_queue)

print语句的结果是0.但是如果我在result_queue中包含enqueue_tasks大小的打印语句,那么在程序运行时,我可以看到大小正在增加事情正在被添加到队列中。

关于发生了什么的想法?

2 个答案:

答案 0 :(得分:2)

您需要使用multiprocessing.Queue,而不是Queue.QueueQueue.Queue 线程安全,不是进程安全的,因此您在一个进程中对其进行的更改不会反映在其他任何进程中。

答案 1 :(得分:1)

看起来这个问题的解决方案更简单。

您正在构建一份期货清单。期货的全部意义在于他们未来的结果。特别是,无论每个函数返回什么,都是未来的(最终)价值。因此,不要将整个结果推到队列中。事情就是这样,只需从任务函数中返回它们,然后从期货中提取它们。


执行此操作的最简单方法是打破该循环,以便每个键都是一个单独的任务,具有单独的未来。我不知道这是否适合您的真实代码,但如果是:

def do_task(key):
    try:
        return perform_scan.delay(key)
    except:
        print "failed"

def main():
    executor = concurrent.futures.ProcessPoolExecutor(10)
    futures = [executor.submit(do_task, key) for key in key_list]
    # If you want to do anything with these results, you probably want
    # a loop around concurrent.futures.as_completed or similar here,
    # rather than waiting for them all to finish, ignoring the results,
    # and printing the number of them.
    concurrent.futures.wait(futures)
    print len(futures)

当然,这并不是分组。但你需要吗?

分组必要的最可能原因是任务非常小,以至于调度它们(以及酸洗输入和输出)的开销会影响实际工作。如果这是真的,那么你几乎肯定会等到整批完成后才能返回任何结果。特别是考虑到你甚至都没有看到结果,直到他们完成所有工作。 (这个模型"分成组,处理每个组,合并在一起"在数字工作的情况下很常见,其中每个元素可能很小,或者元素可能不是彼此独立的,但是那里是那些足够大或独立于其他工作的群体。)

无论如何,这几乎一样简单:

def do_tasks(keys):
    results = []
    for key in keys:
        try:
            result = perform_scan.delay(key)
            results.append(result)
        except:
           print "failed"
    return results

def main():
    executor = concurrent.futures.ProcessPoolExecutor(10)
    futures = [executor.submit(enqueue_tasks, group) for group in grouper(key_list, 40)]
    print sum(len(results) for results in concurrent.futures.as_completed(futures))

或者,如果您愿意先等待然后再计算:

def main():
    executor = concurrent.futures.ProcessPoolExecutor(10)
    futures = [executor.submit(enqueue_tasks, group) for group in grouper(key_list, 40)]
    concurrent.futures.wait(futures)
    print sum(len(future.result()) for future in futures)

但同样,我怀疑你甚至需要这个。