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