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
相關文章
相關標籤/搜索