在Celery中,我正在运行一个主要任务,为查询中的每个项目运行一个子任务。子任务应该并行运行。在UI上,我有一个进度条,显示总计完成了多少子任务。我正在更新主要任务状态以将信息提供给进度条。我的问题是主要任务在将所有子任务推送到代理后立即结束,因此我不能再更新他的状态。我希望主要任务可以等到所有子任务完成。可能吗?还有其他方法吗?这是我的伪代码(真正的代码不使用全局; - ))。
total = 0
done = 0
@task(ignore_result=True)
def copy_media(path):
global total, done
copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})
documents = Document.objects.all()
total = documents.count()
copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})
for document in documents:
process_doc.delay(document, path, copy_media)
@task(ignore_result=True)
def process_doc(document, path, copy_media):
global total, done
# Do some stuff
done += 1
copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})
答案 0 :(得分:0)
我找到了使用TaskSet
的方法。但我并不完全满意,因为我无法忽略子任务的结果。如果我忽略process_doc
任务的结果results.ready()
总是返回False
,results.completed_count()
总是返回0,等等。这是代码:
@task(ignore_result=True)
def copy_media(path):
copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})
documents = Document.objects.all()
total = documents.count()
copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})
job = TaskSet(tasks=[process_doc.subtask((document, path))
for document in documents])
results = job.apply_async()
doc_name = ''
while not results.ready():
done = results.completed_count()
if done:
last = done - 1
for idx in xrange(last, -1, -1):
if results[idx].ready():
doc_name = results[idx].result
break
copy_media.update_state(state=STARTED, meta={'total': total, 'done': done, 'doc-name': doc_name})
time.sleep(0.25)
@task()
def process_doc(document, path):
# Do some stuff
return document
答案 1 :(得分:0)
您可以使用memcached支持的缓存来存储完整任务的数量。在django缓存API中甚至有cache.inrc
用于原子增量,以确保并发计数更新不会搞砸。
此外,在所有子任务完成之前保持主要任务运行是个坏主意,因为你基本上阻止了一个芹菜工人很长一段时间。如果使用一个工作进程运行celery,这将导致永无止境的锁定。
答案 2 :(得分:-1)
我不知道您正在运行哪种版本的芹菜,但您可以查看Group子任务(3.0中的新增功能)。