当我有以下内容时
group1 = group(task1.si(), task1.si(), task1.si())
group2 = group(task2.si(), task2.si(), task2.si())
workflow = chain(group1, group2, task3.si())
直观的解释是task3只应在第2组中的所有任务完成后执行。
实际上,任务3在group1启动但尚未完成时执行。
我做错了什么?
答案 0 :(得分:18)
我和芹菜有同样的问题,试图建立一个工作流程,第一步是“产生一百万个任务”。尝试了一组小组,子任务,最终我的step2在第一步结束之前开始。
长话短说我可能已经找到了使用和弦和哑灵的解决方案:
@celery.task
def chordfinisher( *args, **kwargs ):
return "OK"
什么都不做,但它让我这样做:
tasks = []
for id in ids:
tasks.append( mytask.si( id ) )
step1 = chord( group( tasks ), chordfinisher.si() )
step2 = ...
workflow = chain( step1, step2 )
最初我想在子任务中使用step1,但出于与怀疑相同的原因,调用组的操作结束,任务被认为已完成,我的工作流程继续...
如果有人有更好的东西,我很感兴趣!
答案 1 :(得分:16)
事实证明,在芹菜中你不能把两个小组连在一起 我怀疑这是因为与任务链接的组自动成为一个和弦 - >芹菜文档:http://docs.celeryproject.org/en/latest/userguide/canvas.html
将一个组与另一个任务链接在一起会自动升级 这是一个和弦:
组返回父任务。当将两个组链接在一起时,我怀疑当第一组完成时,和弦启动回调“任务”。我怀疑这个“任务”实际上是第二组的“父任务”。我进一步怀疑这个父任务一旦完成开始组中的所有子任务就完成,结果是第二组执行后的下一个项目。
为了证明这一点,这里有一些示例代码。你需要已经有一个正在运行的芹菜实例。
# celery_experiment.py
from celery import task, group, chain, chord
from celery.signals import task_sent, task_postrun, task_prerun
import time
import logging
import random
random.seed()
logging.basicConfig(level=logging.DEBUG)
### HANDLERS ###
@task_prerun.connect()
def task_starting_handler(sender=None, task_id=None, task=None, args=None, kwargs=None, **kwds):
try:
logging.info('[%s] starting' % kwargs['id'])
except KeyError:
pass
@task_postrun.connect()
def task_finished_handler(sender=None, task_id=None, task=None, args=None, kwargs=None, retval=None, state=None, **kwds):
try:
logging.info('[%s] finished' % kwargs['id'])
except KeyError:
pass
def random_sleep(id):
slp = random.randint(1, 3)
logging.info('[%s] sleep for %ssecs' % (id, slp))
time.sleep(slp)
@task()
def thing(id):
logging.info('[%s] begin' % id)
random_sleep(id)
logging.info('[%s] end' % id)
def exec_exp():
st = thing.si(id='st')
st_arr = [thing.si(id='st_arr1_a'), thing.si(id='st_arr1_b'), thing.si(id='st_arr1_c'),]
st_arr2 = [thing.si(id='st_arr2_a'), thing.si(id='st_arr2_b'),]
st2 = thing.si(id='st2')
st3 = thing.si(id='st3')
st4 = thing.si(id='st4')
grp1 = group(st_arr)
grp2 = group(st_arr2)
# chn can chain two groups together because they are seperated by a single subtask
chn = (st | grp1 | st2 | grp2 | st3 | st4)
# in chn2 you can't chain two groups together. what will happen is st3 will start before grp2 finishes
#chn2 = (st | st2 | grp1 | grp2 | st3 | st4)
r = chn()
#r2 = chn2()