解决同步阻塞的问题
将耗时任务放到后台异步执行,不影响用户其他操作。
实现原理
任务队列是一种跨线程,跨机器的机制。
任务队列中包含称作任务的工作单元。有专门的进程持续不断的监视任务队列,并从中得到新的任务处理。
elery通过消息进行通信,通常使用一个叫Broker(中间人)来协client(任务的发出者)和worker(任务的处理者). clients发出消息到队列中,broker将队列中的信息派发给worker来处理。
一个celery系统可以包含很多的worker和broker,可增强横向扩展性和高可用性能。
broker
RabbitMQ是一个功能完备,稳定的并且易于安装的broker. 它是生产环境中最优的选择。
Redis也是一款功能完备的broker可选项,但是其更可能因意外中断或者电源故障导致数据丢失的情况。 关于是有那个Redis作为Broker,可访下面网址:http://docs.celeryproject.org/en/latest/getting-started/brokers/redis.html#broker-redis
使用
1.创建应用
首先创建tasks.py模块
from celery import Celery # 我们这里案例使用redis作为broker app = Celery('demo', broker='redis://:332572@127.0.0.1/1') # 创建任务函数 @app.task def my_task(): print("任务函数正在执行....")
Celery第一个参数是给其设定一个名字, 第二参数我们设定一个中间人broker, 在这里我们使用Redis作为中间人。my_task函数是我们编写的一个任务函数, 通过加上装饰器app.task, 将其注册到broker的队列中。
现在我们在创建一个worker, 等待处理队列中的任务.打开终端,cd到tasks.py同级目录中,执行命令:
celery -A tasks worker --loglevel=info
2.调用任务
任务加入到broker队列中,以便刚才我们创建的celery workder服务器能够从队列中取出任务并执行。如何将任务函数加入到队列中,可使用delay()。
进入python终端, 执行如下代码:
from tasks import my_task my_task.delay()
3.存储结果
如果我们想跟踪任务的状态,Celery需要将结果保存到某个地方。有几种保存的方案可选:SQLAlchemy、Django ORM、Memcached、 Redis、RPC (RabbitMQ/AMQP)。
例子我们仍然使用Redis作为存储结果的方案,任务结果存储配置我们通过Celery的backend参数来设定。我们将tasks模块修改如下:
from celery import Celery # 我们这里案例使用redis作为broker app = Celery('demo', backend='redis://:332572@127.0.0.1:6379/2', broker='redis://:332572@127.0.0.1:6379/1') # 创建任务函数 @app.task def my_task(a, b): print("任务函数正在执行....") return a + b
我们给Celery增加了backend参数,指定redis作为结果存储,并将任务函数修改为两个参数,并且有返回值。
配置
1.直接通过app来配置
from celery import Celery app = Celery('demo') # 增加配置 app.conf.update( result_backend='redis://:332572@127.0.0.1:6379/2', broker_url='redis://:332572@127.0.0.1:6379/1', )
2.专有配置文件
对于比较大的项目,我们建议配置信息作为一个单独的模块。我们可以通过调用app的函数来告诉Celery使用我们的配置模块。
配置模块的名字我们取名为celeryconfig, 这个名字不是固定的,我们可以任意取名,建议这么做。我们必须保证配置模块能够被导入。
下面我们在tasks.py模块 同级目录下创建配置模块celeryconfig.py:
result_backend = 'redis://:332572@127.0.0.1:6379/2' broker_url = 'redis://:332572@127.0.0.1:6379/1'
tasks.py文件修改为:
from celery import Celery import celeryconfig # 我们这里案例使用redis作为broker app = Celery('demo') # 从单独的配置模块中加载配置 app.config_from_object('celeryconfig')
django使用celery示例
1.创建celery_tasks包
创建main.py config.py 具体的任务包eg:sms
在sms包中创建tasks.py
tasks.py 代码
from celery_tasks.main import app @app.task(name='my_task1') def my_task1(*args, **kwargs): print('执行任务1发送sms短信')
config.py代码
broker_url = "redis://127.0.0.1/14"
main.py代码
from celery import Celery # 为celery使用django配置文件进行设置 import os if not os.getenv('DJANGO_SETTINGS_MODULE'): os.environ['DJANGO_SETTINGS_MODULE'] = 'demo.settings.dev' # 创建celery应用 app = Celery('my_app') # 导入celery配置 app.config_from_object('celery_tasks.config') # 自动注册celery任务 app.autodiscover_tasks(['celery_tasks.sms'])
启动celery
celery -A celry_tasks.main worker -l info
在需要调用任务的模块使用
from celery_tasks.sms import tasks as sms_tasks sms_tasks.send_sms_code.delay(mobile, sms_code, sms_code_expires)