Celery 与 Django

-1.前言

Django原生是单线程的,若是遇到执行时间过长的,只能干等着页面返回,并且不能作别的事情。为了解决这种情况,决定采用异步任务(Celery)的方式。
Celery对Windows的兼容性比较差,建议使用Linux系统。但本篇文章,仍是在Windows上测试的,不要问为何,问就是由于穷。
关于Celery的介绍,咱们已经在另外一篇文章celery概述介绍过了,这一篇是直接干活的文章。示例来自官方文档,本人稍做注释改动。html

环境&版本明细

  • Windows操做系统
  • Python 3.6.8
  • Celery 4.4
  • Django 2.2.2
  • Redis
    注:请提早安装好Python,Django,和Redis.

参考文献

0.目录

<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做为结果存储。**

要将其用于项目,须要执行如下步骤:

  • 安装django-celery-results库:
$ pip install django-celery-results
  • 添加django_celery_results到Django项目的settins.py文件中的INSTALLED_APPS里:
INSTALLED_APPS = (
    ...,
    'django_celery_results',
)
注意:python模块名称是没有短划线的,只有下划线的。
  • 经过执行数据库迁移来建立Celery数据库表:
$ python manage.py migrate celery_results
  • 配置Celery以使用django-celery-results后端
# 若是使用的是Django settings.py配置Celery,添加如下设置:
CELERY_RESULT_BACKEND = 'django-db'
# 对于缓存后端,可使用
CELERY_CACHE_BACKEND = 'django-cache'

django-celery-beat

做用:具备管理界面的数据库支持的按期任务

这个后期单独整理,详情参见官方文档

<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
相关文章
相关标签/搜索