django+celery 中task 值返回到view從而顯示到前端

  1. Django 處理 Request 的基本流程

Django 流程示意圖

上面的這一張是網絡上的 Django 處理 request 的流程示意圖。大致意思就是:

瀏覽器發起 http 請求 ----> http handling(request 解析) ----> url 匹配(正則匹配找到對應的 View) ----> 在View中進行邏輯的處理與數據計算(包括調用 Model 類進行數據庫的增刪改查)----> 將數據推送到 template,返回對應的 template/response。
對於一些簡單的操作,可以放在 View 中處理。在View處理任務時用戶處於等待狀態,直到頁面返回結果。但是對於一些複雜的操作,則在 View 中應該先返回 response,再在後臺處理任務。用戶無需等待。當任務處理完成時,我們可以再通過 Ajax 之類的方式告知用戶。
Celery 就是基於 Python 開發的一個分佈式任務隊列框架,支持使用任務隊列的方式在分佈的機器/進程/線程上執行任務調度。

  1. Celery

Celery 的基本架構

上圖是 Celery 的基本架構,它採用典型的生產生--消費者模式,主要由三部分組成:broker(消息隊列)、workers(消費者:處理任務)、backend(存儲結果)。實際應用中,用戶從 Web 前端發起一個請求,我們只需要將請求所要處理的任務丟入任務隊列 broker 中,由空閒的 worker 去處理任務即可,處理的結果會暫存在後臺數據庫 backend 中。我們可以在一臺機器或多臺機器上同時起多個 worker 進程來實現分佈式地並行處理任務。

  1. 安裝 Celery
    安裝過程就是直接按照官網上的文檔安裝即可。我這裏用的均是目前的最新穩定版。

macOS Sierra 10.12.3
Django 1.10
Celery 4.0.2

在早前版本的 Celery 中,有一個專門供 Django 使用的 Celery 版本:django-celery。但是在現在 Celery 已經統一爲一個版本,所以直接安裝原生的 Celery 即可:
pip install celery

Celery 推薦使用 RabbitMQ,Redis,Amazon SQS,Zookeeper,這幾個作爲 broker,但是隻有前兩個支持在生產環境使用。下面的表格對比了幾種 broker。

Name
Status
Monitoring
Remote Control

RabbitMQ
Stable
Yes
Yes

Redis
Stable
Yes
Yes

Amazon SQS
Stable
No
No

Zookeeper
Experimental
No
No

我是使用 Redis 作爲 broker 的。除了安裝 redis 之外,還應該安裝 redis 的 python 支持庫。
安裝 Redis:
brew install redis

安裝 redis 的 python 支持庫:
pip install redis

輸入 redis-server 來開啓 redis。當你看見下面的圖案時,就說明成功開啓了 redis。redis 默認監聽 6379 端口。開啓之後可以用 ctrl+c 來退出。

開啓 redis

  1. 把 Celery 配置到 Django 上
    假設你有一個項目 proj:
    • proj/
    • proj/init.py
    • proj/settings.py
    • proj/urls.py
    • manage.py

Celery 建議在 proj/proj/celery.py 上定義一個 Celery 的實例。
文件 proj/proj/celery.py:
from future import absolute_import, unicode_literals
import os
from celery import Celery

set the default Django settings module for the 'celery' program.

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')

app = Celery('proj')

Using a string here means the worker don't have to serialize

the configuration object to child processes.

- namespace='CELERY' means all celery-related configuration keys

should have a CELERY_ prefix.

app.config_from_object('django.conf:settings', namespace='CELERY')

Load task modules from all registered Django app configs.

app.autodiscover_tasks()

@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))

然後再在proj/proj/init.py做一些配置。
文件 proj/proj/init.py:
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.

from .celery import app as celery_app

all = ['celery_app']

完成上面的步驟之後,可以在命令行輸入:
celery worker -A proj -l info

正常情況下,應該會出現類似於下圖的輸出。

開啓 celery 並與 redis 連接

ok,接下來,爲了讓 celery 中執行的任務的結果返回我們的 Django,我們還應該安裝 django-celery-results。
pip install django-celery-results

再在 proj/proj/settings.py: 中做如下的設置:
文件proj/proj/settings.py:

Celery 設置

CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_BACKEND = 'django-db'
CELERY_TIMEZONE = 'Asia/Shanghai'

INSTALLED_APPS = [
...
...
'django_celery_results'
]

再 migrate 一下:
migrate django_celery_results

  1. 加入一個耗時任務
    在你的 app 的目錄下,新建一個 tasks.py 文件。在裏面加入一個耗時的任務:
    from future import absolute_import, unicode_literals
    from celery import shared_task

模擬一個耗時操作

@shared_task
def longtime_test():
...

在這裏進行一些耗時操作

...

在 views.py 中,寫成這樣:
def test_view(request):

do something

longtime_test.delay()
return render(request, 'template.html', {'data': data})

這樣之後,就會先返回 html 模版,再在後臺計算數據了。

作者:柴柴土
鏈接:https://www.jianshu.com/p/6f8576a37a3e
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章