Django原生是单线程的,若是遇到执行时间过长的,只能干等着页面返回,并且不能作别的事情。为了解决这种情况,决定采用异步任务(Celery)的方式。
Celery对Windows的兼容性比较差,建议使用Linux系统。但本篇文章,仍是在Windows上测试的,不要问为何,问就是由于穷。
关于Celery的介绍,咱们已经在另外一篇文章celery概述介绍过了,这一篇是直接干活的文章。示例来自官方文档,本人稍做注释改动。html
<h2 id=1>1.Using Celery with Django</h2> >Celery以前须要一个单独的库(djcelery)与Django一块儿使用,可是从3.1.x(ps:3.1以后就是4.x版本)之后就再也不使用了。只须要安装好Celery,Django就能够直接使用了。通过测试发现Celery4.x版本依然能够是和djcelery一块儿使用,但真的不必。 python
要将Celery与Django项目一块儿使用,必须首先定义Celery库的实例(称为"app")。
若是已经有了一个Django项目,例如:git
- proj/ - manage.py - proj/ - __init__.py - settings.py - urls.py
那么建议的方法是建立一个新的proj/proj/celery.py
模块,该模块定义Celery实例:
文件: proj/proj/celery.pygithub
from __future__ import absolute_import, unicode_literals import os from celery import Celery # set the defalut Django settings module for the 'celery' program # 为"celery"程序设置默认的Django settings 模块 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings') app = Celery('proj') # Using a string here means the worker dosen't have to serialize the configuration object to child processes. # 在这里使用字符串意味着worker没必要将配置对象序列化为子进程。 # - namespace='CELERY' means all celery-related configuration keys should have a 'CELERY_' prefix # namespace="CELERY"表示全部与Celery相关的配置keys均应该带有'CELERY_'前缀。 app.config_from_object('django.conf:settings', namespace='CELERY') # Load task modules from all registered Django app configs. # 从全部注册的Django app 配置中加载 task模块。 app.autodiscover_tasks() @app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request))
而后,须要将此模块proj/proj/celery.py导入proj/proj/init.py中。这样能够确保再Django启动时加载该应用,以便@shared_task装饰器(稍后说起)将使用该应用。
文件:proj/proj/init.pyredis
from __future__ import absolute_import, unicode_literals # This will make sure the app is always imported when Django starts so that shared_task will use this app. 这将确保在Django启动时始终导入应用程序,以便shared_task使用该应用程序。 from .celery import app as celery_app __all__ = ('celery_app',)
<h2 id=2>2.详解celery.py模块</h2> 接下来分解一下celery.py模块中发生的状况,更好的来理解。 首先咱们从[__future__](http://python-future.org/)中导入`absolute_import`,这样celery.py模块就不会与库冲突: ``` from __future__ import absolute_import ``` 而后,为celery命令行程序设置默认**DJANGO_SETTINGS_MODULE**的环境变量: ``` os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings') ``` 您不须要此行,可是能够避免始终将设模块传递到celery程序中。他必须始终在建立应用程序实例以前出现,接下来要作的是: ``` app = Celery('proj') ``` 这是Celery库实例,能够有不少实例,可是使用Django时真的不必这么干。 咱们还须要将**Django settings**模块添加为Celery的配置源。这意味着能够没必要使用多个配置文件,从而直接从Django settings中配置Celery。也能够根据要将他们分开。。 ``` app.config_from_object('django.conf:settings', namespace='CELERY') ``` 大写命名空间意味着全部[Celery配置选项](https://docs.celeryproject.org/en/4.4.0/userguide/configuration.html#configuration)必须以大写而不是小写指定,并以开头CELERY_,例如,**task_always_eager**设置为**CELERY_TASK_ALWAYS_EAGER**。这也适用于工做程序设置,例如,**worker_concurrency**设置为**CELERY_WORKER_CONCURRENCY**。 能够直接传递设置对象,建议使用字符串,由于那样,worker就没必要序列化该对象。该`CELERY_`命名空间也是可选的,可是建议使用这个,为了更好的识别和防止与其余设置冲突。 在这里我简单的罗列一下个人设置,有啥需求的,本身点击官方文档[Celery配置选项](https://docs.celeryproject.org/en/4.4.0/userguide/configuration.html#configuration)去学习。数据库
文件:Django的settings.pydjango
CELERY_BROKER_URL = 'redis://localhost:6379/1' # Broker配置,使用Redis做为消息中间件 CELERY_RESULT_BACKEND = 'redis://localhost:6379/2' # Backend设置,使用redis做为后端结果存储 CELERY_TIMEZONE = 'Asia/Shanghai' CELERY_ENABLE_UTC = False CELERY_WORKER_CONCURRENCY = 99 # 并发的worker数量 CELERY_ACKS_LATE = True CELERY_WORKER_MAX_TASKS_PER_CHILD = 5 # 每一个worker最多执行的任务数, 可防止内存泄漏 CELERY_TASK_TIME_LIMIT = 15 * 60 # 任务超时时间
接下来,可重用的应用程序单独常见作法是在一个单独的tasks.py模块中定义全部任务,而Celery能够自动发现这些模块:windows
app.autodiscover_tasks()
使用上边这一行,Celery将按照约定自动发现全部已经安装的app中的tasks.py
。后端
- app1/ - tasks.py - models.py - app2/ - tasks.py - models.py
这样,就能够没必要手动将单个模块添加到CELERY_IMPORTS设置中。缓存
最后,该debug_task
示例是一个转储其本身的请求信息的任务。这是使用Celery3.1中引入的新 bind=True任务选项,能够轻松地引用当前任务实例。
<h2 id=3>3.使用@shared_task装饰器</h2> 您编写的任务可能会存在于可重用的app中,而且可重用的apps不能依赖于项目自己,所以您也不能直接导入app实例。 该@shared_task装饰器可让你无需任何具体的app实例建立任务:
文件:app1/tasks.py
from __future__ import absolute_import, unicode_literals from celery import shared_task @shared_task def add(x, y): return x + y @shared_task def mul(x, y): return x * y @shared_task def xsum(numbers): return sum(numbers)
调用任务,函数.delay(参数),示例以下:
from app1.tasks import add res = add.delay(2, 3) res.get()
附:官方完整示例代码:[https : //github.com/celery/celery/tree/master/examples/django/](https : //github.com/celery/celery/tree/master/examples/django/)
<h2 id=4>4.扩展</h2> #### django-celery-results 做用:**使用Django ORM/Cache做为结果存储。**
要将其用于项目,须要执行如下步骤:
$ pip install django-celery-results
INSTALLED_APPS = ( ..., 'django_celery_results', ) 注意:python模块名称是没有短划线的,只有下划线的。
$ python manage.py migrate celery_results
# 若是使用的是Django settings.py配置Celery,添加如下设置: CELERY_RESULT_BACKEND = 'django-db' # 对于缓存后端,可使用 CELERY_CACHE_BACKEND = 'django-cache'
做用:具备管理界面的数据库支持的按期任务
这个后期单独整理,详情参见官方文档
<h2 id=5>5.启动worker进程</h2> In a production environment you’ll want to run the worker in the background as a daemon - see Daemonization - but for testing and development it is useful to be able to start a worker instance by using the celery worker manage command, much as you’d use Django’s manage.py runserver
在生产环境中,你会想要在后台做为守护程序运行woerker, 详情参见官方文档系统守护进程
对于测试和开发环境,能够经过使用Celery worker 管理命令启动,就像Django的 manage.py runserver
:
# Linux 操做系统 # 首先,启动redis,省略 # 其次,启动Django项目,省略 # 最后,启动celery worker $ celery -A 项目名称 worker -l info # Windows 操做系统 redis-server.exe redis.windows.conf python manage.py runserver celery -A 项目名称 worker -l info -P eventlet
更多命令详解,使用help命令:
$ celery help