如何使用工作人员初始化中使用的变量来启动celery worker

时间:2018-12-21 19:01:28

标签: python celery

是否可以选择在启动时将变量传递给celery worker并在执行时在worker内部使用它?

我正在编写服务器,它将负责机器学习培训和评估。我想动态启动worker的新实例并将变量传递给它,该变量将用于在其中加载特定模型。

我发现了如何使用worker_main方法从答案here开始工作。

我在考虑两种解决方案:

  1. 将其设置为环境变量。该解决方案的问题在于,当同时创建两个worker实例时,它可能会损坏。

  2. 将其作为argv传递,但我不知道如何在worker中读取变量。


编辑

我发现了this线程,但是它只谈论访问任务中的自定义参数。我的问题是关于在工作程序初始化时访问它。

this线程的启发,我将尝试使用芹菜信号。 http://docs.celeryproject.org/en/latest/userguide/signals.html#worker-init

2 个答案:

答案 0 :(得分:4)

也许我的问题不够准确,但是我自己找到了文档和stackoverflow线程的答案。

我想为Keras模型运行一个单独的工人。在工作程序初始化中,我需要将模型加载到内存中,而在任务模型中,我将其用于预测。

我的解决方案:

  1. 具有 model_id 的名称工作者(由于id是唯一的,每个模型我只需要一个工作者)
  2. celeryd_after_setup 信号函数上,我解析了名称并在worker中设置了全局变量
  3. worker_process_init 信号函数中,我加载的模型是Grasper类中的静态字段
  4. 在任务中,我使用了Grasper类中的静态字段

下面是一些精确描述解决方案的代码。

from celery.signals import worker_process_init, celeryd_after_setup
from celery.concurrency import asynpool

# my custom class containing static fields for model and tokenizer
# it also can be global variable as model_id
from myapp.ml import Grasper

# set to have some time for model loading otherwise worker_process_init can terminate
asynpool.PROC_ALIVE_TIMEOUT = 100.0
model_id = None

@celeryd_after_setup.connect()
def set_model_id(sender, instance, **kwargs):
    global model_id
    model_id = instance.hostname.split('@')[1]

@worker_process_init.connect()
def configure_worker(signal=None, sender=None, **kwargs):
    Grasper.load_model(model_id)

然后在celery任务中,可以对已加载的模型使用Grasper类。 此解决方案有效,但是我知道还有改进的地方,因此,如果您有任何想法请发表评论。

答案 1 :(得分:0)

在派生/生成子流程时,环境变量从父级复制到子级。这意味着该进程可以操纵自己的变量,但其他进程则不能(可能,但例外-请在以下背景下阅读此线程:Is there a way to change the environment variables of another process in Unix?

如果您自己的代码中存在竞争条件的问题,则应考虑锁定对父项os.environ进行变异并生成工作程序的部分。在工人作为单独的进程生成之后,释放锁,您就不必担心通过修改父级的环境来破坏孩子了。