Python 在完成所有任务后运行任务

Python 在完成所有任务后运行任务,python,rabbitmq,celery,Python,Rabbitmq,Celery,我正在编写一个应用程序,它需要并行运行一系列任务,然后运行一个包含所有任务运行结果的单个任务: @celery.task def power(value, expo): return value ** expo @celery.task def amass(values): print str(values) 这是一个非常做作和过于简单的例子,但希望这一点能得到很好的理解。基本上,我有许多项目需要运行power,但我只想对所有任务的结果运行amass。所有这些都应该异步进行,

我正在编写一个应用程序,它需要并行运行一系列任务,然后运行一个包含所有任务运行结果的单个任务:

@celery.task
def power(value, expo):
    return value ** expo

@celery.task
def amass(values):
    print str(values)
这是一个非常做作和过于简单的例子,但希望这一点能得到很好的理解。基本上,我有许多项目需要运行
power
,但我只想对所有任务的结果运行
amass
。所有这些都应该异步进行,我不需要从
amass
方法返回任何内容

有人知道如何在芹菜中设置它,以便异步执行所有操作,并在所有操作完成后调用带有结果列表的单个回调吗

我已将此示例设置为按照Alexander Afanasiev的建议使用
和弦运行:

from time import sleep

import random

tasks = []

for i in xrange(10):
    tasks.append(power.s((i, 2)))
    sleep(random.randint(10, 1000) / 1000.0) # sleep for 10-1000ms

callback = amass.s()

r = chord(tasks)(callback)
不幸的是,在上面的示例中,
tasks
中的所有任务只有在调用
chord
方法时才会启动。是否有一种方法可以让每个任务单独启动,然后我可以向组中添加一个回调,以便在完成所有任务后运行?

芹菜可以为您想象的大多数工作流提供支持

看来你需要好好利用一下。以下是docs的报价:

和弦就像一个组,但有回调。和弦包括 标题组和正文,其中正文是应 在标头中的所有任务完成后执行


@alexander afanasiev给你的答案基本上是正确的:使用和弦

您的代码还可以,但是
tasks.append(power.s((i,2))
实际上并没有执行子任务,只是添加到列表中。它是
chord(…)(…)
向代理发送的消息数量与您在
tasks
列表中定义的子任务数量相同,另外还有一条消息用于回调子任务。当您调用
chord
时,它会尽快返回


如果您想知道和弦何时完成,您可以像使用示例中的
r.ready()
一样使用单个任务来轮询完成情况。

以下是一个适合我的解决方案:

任务。py

from time import sleep

import random

@celery.task
def power(value, expo):
    sleep(random.randint(10, 1000) / 1000.0) # sleep for 10-1000ms
    return value ** expo

@celery.task
def amass(results, tasks):
    completed_tasks = []
    for task in tasks:
        if task.ready():
            completed_tasks.append(task)
            results.append(task.get())

    # remove completed tasks
    tasks = list(set(tasks) - set(completed_tasks))

    if len(tasks) > 0:
        # resend the task to execute at least 1 second from now
        amass.delay(results, tasks, countdown=1)
    else:
        # we done
        print results
用例:

tasks = []

for i in xrange(10):
    tasks.append(power.delay(i, 2))

amass.delay([], tasks)

这应该做的是尽快异步启动所有任务。一旦它们都被发布到队列中,
amass
任务也将被发布到队列中。在所有其他任务完成之前,聚合任务将继续重新发布自身

看看你问题中的这个片段,它看起来像是在传递一个
列表
作为和弦标题,而不是一个

from time import sleep
import random

tasks = []

for i in xrange(10):
    tasks.append(power.s((i, 2)))
    sleep(random.randint(10, 1000) / 1000.0) # sleep for 10-1000ms

callback = amass.s()

r = chord(tasks)(callback)
列表
转换为
会导致您预期的行为:

...

callback = amass.s()

tasks = group(tasks)

r = chord(tasks)(callback)

这是绝对正确的,但是,它有一个问题。我已经用细节更新了我的答案。我希望每个子任务在发布后立即执行,而不是在发布和弦时执行。这可能吗?好吧,在循环中执行一个
power.delay(i,2)
,在调用
amass(results)
之前轮询所有中间结果以完成。但我真的不明白重点。使用chord将在代理中的
power.s
子任务作为消息提供后立即执行,并在完成后执行
amass
。我认为你应该明确你想要实现什么,因为您异步执行任务的愿望似乎与您建议的用法相矛盾。我提出了一个解决方案,上面演示了我想做的事情。我想您刚刚重新实现了
chord
函数。一点也不:我想您不明白我的要求。chord函数在被调用之前不会开始执行任务。然而,在我的代码中,任务立即开始执行,然后完成处理程序也被发布到队列中。在我的用例中,我不会调用实际的chord函数,直到将来的某个时候,我已经开始了工作的所有必要任务。从本质上讲,chord函数是惰性的,只有当任务都被发布并且chord函数被调用时才开始执行任务。我的实现非常迫切,因为它会尽快启动所有任务。嗨,看起来上面的方法是一个很好的方法,至少在概念上是这样。但是,当我尝试使用与上面完全相同的代码时,它抛出了以下错误:
encoderror:is not JSON serializable
非常感谢您的帮助。好的,我通过传递最后的_任务()解决了上面的错误TaskID列表本身直接传递,而不是像上面的代码示例中那样传递任务对象列表。无论如何,谢谢你的回答。这帮了大忙。投票!如果每个小组开始一项新任务,你想让和弦说等待每个小组的子任务完成,那么你知道这是如何工作的吗?或者,我已经有一段时间没有详细研究芹菜了,所以我不知道4.x是如何工作的