当前位置: 首页 > 后端技术 > Python

Celery杂谈

时间:2023-03-26 16:48:05 Python

在这篇文章中,我不会对celery的一些话题进行深入的介绍,而是记录下我在学习和使用celery过程中遇到的一些困惑。1、芹菜有什么作用?celery的官方文档说celery是一个分布式任务队列,但是开发者很难通过阅读它的官方文档来感受它是分布式的,因为官方并没有提供分布式代码示例和相关说明。Celery对消息队列进行了封装,比如常用的伪消息队列如rabbitmq、kafka、nysql、redis等,它用类似rabbitmq和kafak的概念抽象了mysql和redis。事实上,celery本身并不针对这些消息。队列是抽象出来的,但是用了很多kombu代码。kombu底层是消息队列的真正抽象。为什么芹菜还要封装一层?Celery其实是抽象了消息队列中生产者和消费者的用法,而kombu是抽象了消息队列的用法。在celery的世界里,可以忽略生产者和消费者的概念,只考虑任务的概念。Celery帮助开发人员将要执行的功能封装到任务中。一旦任务被调用,它将在本地机器或远程机器上执行。这样,开发人员就可以专心编写业务逻辑。2.celery中的tasks是如何执行的@app.taskdefadd(x,y):returnx+y我们在使用的时候会像上面的代码一样用装饰器把我们的函数包装起来形成一个task。这个Task当我们调用add.delay(1,2)时,其实是调用了消息队列中的生产者。根据celery配置文件,或者装饰器传入的参数,选择路由和队列,将任务发送给消费者。.消费者获取到任务后,会将任务扔到进程池、线程池、协程中的其中一种策略中运行任务。生产者发送的肯定是任务的元数据信息,肯定不会发送过去一个对象的序列化格式。这不是不可能,但不建议这样做。最重要的元数据是任务的ID和名称。消费者会根据任务名寻找要执行的任务,消费者如何根据任务名寻找要执行的任务,见下一节。3、celery消费者如何根据任务名找到要执行的任务?用celery写的任务文件不仅要存在于producer(分发任务的机器)上,还要在consumer(启动worker的机器)d上存在,这样才能在数据结构中注册任务,并且worker只有在收到任务的元数据后才会找到要执行的任务。官方文档中没有样例,也没有明确的解释,所以很迷惑。分布式的,有四种方式可以让worker(消费者)在启动时注册所有的task。1)将Celery实例和所有任务写入同一个文件中mkdir/root/projectcd/root/projecttouch__init__.pytouchcelery.pycatcelery.pyfromceleryimportCeleryapp=Celery(include=["project.tasks"])touchtasks。pycattasks.pyfromproject.celeryimportapp@app.taskdefadd(x,y):reurnx+y@app.taskdefsub(x,y):returnx-y这样在启动worker的时候就指定项目中的Celery实例所在路径。这时装饰器会同时执行和注册任务。不过这种方法对于平时单纯的写脚本还是不错的。如果在工程项目中过于混乱,没有分类,所有的任务都在一个文件中,不清晰,没有层次感。2)worker启动时命令行有一个-I参数选项。此选项可以用逗号分隔,并传入一个或多个任务文件路径。例如,有两个任务。3)执行Celery类实例化时as建议传入参数app=Celery(include=["project.tasks"])4)在配置文件中指定有一项CELERY_IMPORTS=("project.tasks",)在Celery的用户配置文件中,这种方式更加灵活,易于维护。将celery实例和相关任务写入文件是最不推荐在项目中使用的。如果是简单的工具,没有问题,通过命令行导入也不是很容易。优雅,无论使用3和4中的哪一个,都需要保持分发任务和所有worker机器的一致性,所以最好使用配置文件,修改文件时统一分发到每台机器上。