【问题标题】:Celery: can a task be created from inner function?芹菜:可以从内部函数创建任务吗?
【发布时间】:2020-06-07 19:22:37
【问题描述】:

我有一个芹菜任务:

@task
def foo():
  part1()
  part2()
  part3()

...我正在分解成一系列子任务

@task
def foo():
  @task
  def part1():
    ...

  @task
  def part2():
    ...

  @task
  def part3():
    ...

  chain(part1.s(), part2.s(), part3.s()).delay()

子任务是内部函数,因为我不希望它们在父任务的上下文之外执行。问题是我的工作人员没有检测和/或注册内部任务(我使用autoregister 来发现应用程序和任务模块)。如果我将它们移到模块中与父任务foo 相同的级别,则可以正常工作。

celery 支持内部函数作为任务吗?如果是这样,我如何让工人注册?

【问题讨论】:

    标签: python celery celery-task


    【解决方案1】:

    您的代码的问题是每次调用foo() 时都会得到part1 的新定义。另请注意,在您调用 foo 之前不会创建单个 part1 函数,因此 celery 无法在初始化工作线程时注册要创建的任何 part 函数。

    我认为以下代码最接近您想要的。

    def make_maintask():
        @task
        def subtask1():
            print("do subtask")
    
        # ...
    
        @task
        def _maintask():
            chain(subtask1.si(), subtask2.si(), subtask3.si()).delay()
    
        return _maintask
    
    
    maintask = make_maintask()
    

    这样,subtask 等的每个定义从外部是不可见的。

    一些cmets

    • 如果您只想隐藏subtask,请三思。 python 语言的设计者并不认为需要像 java 中那样需要公共和私有的访问控制。这是一种使语言严重复杂化的功能,具有可疑的优势。我认为组织良好的包和模块以及好的名称(例如在前面添加下划线)可以解决您的所有问题。

    • 如果_maintask 所做的只是将子任务委托给其他子进程,那么您实际上不需要将其定义为 celery 任务。除非你真的需要,否则不要让一个 celery 任务调用另一个 celery 任务。

    【讨论】:

    • 我不知道不建议在任务中调用delay()。我认为这是必要的,尤其是在使用在任务中价值有限的画布时,除非您在其上调用delay()。文档没有明确说明这种客户/工人的区别。您能否指出不建议在任务中调用异步任务的参考资料?
    • @Neil 抱歉,我找不到关于该主题的温和介绍。 Introduction to Celery 可能会有所帮助,但我认为学习这些东西的最好方法是稍微玩一下。你可以让你的函数打印一些值并观察它们。
    • 我想将我的任务分解为并行执行的子任务,以避免单个长时间运行的任务。但我也不想将单个任务的所有逻辑部分暴露给“客户端”并让它们独立运行。所以我假设一个可接受的模式是从其他任务中调用异步任务
    • 我使用 Celery 已经有一段时间了,并且一直遵循这种从其他异步任务中调用异步子任务的方法。我在 Celery 方面没有观察到这样做的行为问题。这就是为什么我对您的评论感到惊讶并想看看它是否被记录在案。在其他 SO 问题中有很多这种模式的例子,尽管 Celery 文档在这种方式上似乎并不明确
    • @Neil 您确定要使用chain 来并行化您的任务吗?我不认为chain 可以做到这一点..
    猜你喜欢
    • 2021-05-30
    • 1970-01-01
    • 2016-03-31
    • 2012-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    相关资源
    最近更新 更多