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

Python 多重处理后,我的队列为空。进程实例完成,python,queue,multiprocessing,celery,concurrent.futures,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.d

我有一个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\u 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。然而,如果我在
enqueue\u tasks
中包含一个大小为
result\u queue
的print语句,当程序运行时,我可以看到该语句的大小正在增加,并且正在向队列添加内容


关于正在发生什么的想法?

您需要使用队列,而不是
队列。队列
<代码>队列。队列是线程安全的,而不是进程安全的,因此您在一个进程中对它所做的更改不会反映在任何其他进程中。

您需要使用,而不是
队列。队列
<代码>队列。队列是线程安全的,而不是进程安全的,因此您在一个进程中对它所做的更改不会反映在任何其他进程中。

似乎有一个更简单的解决方案可以解决此问题

你正在建立一个未来的清单。未来的全部意义在于它们是未来的结果。特别是,无论每个函数返回什么,都是未来的(最终)值。所以,根本不要做“将结果推送到队列上”的事情,只需从任务函数返回结果,然后从未来函数中提取结果


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

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)

不过,我还是怀疑你是否需要这个。

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

你正在建立一个未来的清单。未来的全部意义在于它们是未来的结果。特别是,无论每个函数返回什么,都是未来的(最终)值。所以,根本不要做“将结果推送到队列上”的事情,只需从任务函数返回结果,然后从未来函数中提取结果


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

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)

不过,我还是怀疑你是否需要这个。

还要注意,我在你之前关于这个话题的问题中提到了这一点。如果我不明白我的意思,我道歉。我感谢你的帮助!你不可能知道,因为我没有给出我的问题的背景。还要注意,我在你之前关于这个主题的问题中提到了这一点。如果我不明白我的意思,我道歉。我感谢你的帮助!如果
perform\u scan.delay()
是一个异步远程调用,这可能意味着它不进行任何处理,只是在等待响应,那么为什么要首先使用进程而不是线程?如果
perform\u scan.delay()
是一个异步远程调用,这可能意味着它不进行任何处理,只是在等待响应,为什么首先要使用进程而不是线程?我的眼睛已经睁开了。我甚至不知道为什么我不认为期货是一个简单的列表理解——这完全违背了我的中介队列的目的,正如你所说的(在你的评论中建立另一个评论)。我还进行了分组--我想分组的方式不对。似乎我不需要它,因为即使我的个人任务很小,我也不想在最后看任何一个。有一件事我不明白,“未来。结果”。我认为未来是实际的结果,未来是它自己的目标吗?@jeffrey:是的,未来是一个拥有可能还不可用的结果的对象。可以围绕隐式未来(参见AliceML或任何actor或数据流语言)设计整个语言的并发模型,这可能非常酷,但这不适合Python,因此它有显式未来。请看更多的讨论。我的眼睛已经睁开了。我甚至不知道为什么我不认为期货是一个简单的列表