是否可以选择在启动时将变量传递给celery worker并在执行时在worker内部使用它?
我正在编写服务器,它将负责机器学习培训和评估。我想动态启动worker的新实例并将变量传递给它,该变量将用于在其中加载特定模型。
我发现了如何使用worker_main
方法从答案here开始工作。
我在考虑两种解决方案:
将其设置为环境变量。该解决方案的问题在于,当同时创建两个worker实例时,它可能会损坏。
将其作为argv传递,但我不知道如何在worker中读取变量。
编辑
我发现了this线程,但是它只谈论访问任务中的自定义参数。我的问题是关于在工作程序初始化时访问它。
受this线程的启发,我将尝试使用芹菜信号。 http://docs.celeryproject.org/en/latest/userguide/signals.html#worker-init
答案 0 :(得分:4)
也许我的问题不够准确,但是我自己找到了文档和stackoverflow线程的答案。
我想为Keras模型运行一个单独的工人。在工作程序初始化中,我需要将模型加载到内存中,而在任务模型中,我将其用于预测。
我的解决方案:
下面是一些精确描述解决方案的代码。
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
进行变异并生成工作程序的部分。在工人作为单独的进程生成之后,释放锁,您就不必担心通过修改父级的环境来破坏孩子了。