【问题标题】:Groups of chains with positional arguments in partial tasks using Celery使用 Celery 在部分任务中具有位置参数的链组
【发布时间】:2016-12-14 14:04:44
【问题描述】:

我正在编写一个应用程序,它将异步执行一组多个同步任务链。

换句话说,我可能拥有foo(a,b,c) -> boo(a,b,c) 的一些bs 列表的管道。

我的理解是为这个列表中的每个 b 创建一个foo(a,b,c) | boo(a,b,c) 链。然后这些链将形成一个芹菜组,可以异步应用。

我的代码如下:

my_app.py

#!/usr/bin/env python3

import functools
import time

from celery import chain, group, Celery
from celery.utils.log import get_task_logger

logger = get_task_logger(__name__)

app = Celery("my_app", broker='redis://localhost:6379/0', backend='redis://localhost:6379/0')

@app.task
def foo(a, b, c):
    logger.info("foo from {0}!".format(b))
    return b

@app.task
def boo(a, b, c):
    logger.info("boo from {0}!".format(b))
    return b

def break_up_tasks(tasks):
    try:
        first_task, *remaining_tasks = tasks
    except ValueError as e:
        first_task, remaining_tasks = [], []
    return first_task, remaining_tasks

def do_tasks(a, bs, c, opts):
    tasks = [foo, boo]

    # There should be an option for each task
    if len(opts) != len(tasks):
        raise ValueError("There should be {0} provided options".format(len(tasks)))

    # Create a list of tasks that should be included per the list of options' boolean values
    tasks = [task for opt, task in zip(opts, tasks) if opt]

    first_task, remaining_tasks = break_up_tasks(tasks)

    # If there are no tasks, we're done.
    if not first_task: return

    chains = (
        functools.reduce(
            # `a` should be provided by `apply_async`'s `args` kwarg
            # `b` should be provided by previous partials in chain
            lambda x, y: x | y.s(c),
            remaining_tasks, first_task.s(a, b, c)
        ) for b in bs
    )

    g = group(*chains)
    res = g.apply_async(args=(a,), queue="default")
    print("Applied async... waiting for termination.")

    total_tasks = len(tasks)

    while not res.ready():
        print("Waiting... {0}/{1} tasks complete".format(res.completed_count(), total_tasks))
        time.sleep(1)

if __name__ == "__main__":
    a = "whatever"
    bs = ["hello", "world"]
    c = "baz"

    opts = [
        # do "foo"
        True,
        # do "boo"
        True
    ]

    do_tasks(a, bs, c, opts)

跑步芹菜

celery worker -A my_app -l info -c 5 -Q default

不过,我发现,当我运行上述代码时,我的服务器客户端运行一个无限循环,因为 boo 缺少一个参数:

TypeError: boo() missing 1 required positional argument: 'c'

我的理解是apply_async会为每条链提供argskwarg,而链中之前的链接会为后续的链接提供它们的返回值。

为什么boo 没有正确接收参数?我确信这些任务写得不好,因为这是我第一次涉足 Celery。如果您有其他建议,我很乐意接受。

【问题讨论】:

    标签: python python-3.x asynchronous celery celery-task


    【解决方案1】:

    在调试完您的代码后(我也是 Celery 的新手!:))我了解到,每个链式函数都会将第一个参数替换为前一个链式函数调用的结果 - 所以我相信解决您的问题的方法是在 reduce 中的 y.s 中添加一个缺少的参数(第二个):

    chains = (
        functools.reduce(
            # `a` should be provided by `apply_async`'s `args` kwarg
            # `b` should be provided by previous partials in chain
            lambda x, y: x | y.s(b,c), # <- here is the 'new guy'
            remaining_tasks, first_task.s(a, b, c)
        ) for b in bs
    )
    

    希望对你有帮助。

    【讨论】:

    • 当然,但是将args 提供给Group.apply_async 会做同样的事情。为什么这不起作用?
    • 我相信来自 apply_async 函数的参数被应用到链中的第一个函数 - 下一个将只从它的父函数接收第一个参数。
    • 这里有解释 - docs.celeryproject.org/en/latest/userguide/… - 很难找到有关此功能如何在链上工作的文档。
    猜你喜欢
    • 1970-01-01
    • 2015-10-04
    • 2017-03-27
    • 1970-01-01
    • 2019-01-22
    • 2023-03-05
    • 2016-06-17
    • 2021-04-02
    • 2016-12-25
    相关资源
    最近更新 更多