其實。。。這篇教程不包括郵箱驗證的,不過我有實現個 celery + django 的郵箱驗證博客,文末附 repo 。

Web 應用中的長時操作如果沒有非同步實現會阻塞代碼運行,用戶需要等待較長時間才能收到響應。而像 Celery 這樣的非同步工具就能很好解決這類問題。本文將帶你瞭解 Django 框架下的 Celery 使用。

安裝

Celery

Celery 使用 pip 安裝即可。

pip install celery

Celery 還需要 broker,貌似有翻譯成中間人的,類似個消息隊列。這裡將使用 Redis 作為 broker。redis 安裝如下:

wget http://download.redis.io/releases/redis-3.2.8.tar.gztar xzf redis-3.2.8.tar.gzcd redis-3.2.8makemake test

此時 src 文件夾下應該就有了 redis-server 和 redis-cli 二進位文件,可以把它們複製到 /usr/local/bin 目錄下方便以後使用。此處暫不複製,啟動 redis 伺服器,使用默認埠 6379 。

redis-server

保持 redis 服務開啟,生產環境下建議參考 redis 入門指南 進行 redis 配置。

Django

Celery 4 支持 Django 1.8 以上版本,已經不需要安裝其它包。

pip install django=1.9

Django 項目

啟動一個 Django 項目,並創建一個應用名為 Project ,創建一個應用叫 celeryExample。

django-admin startproject Projectcd Projectpython manage.py startapp celeryExample

在 Project/Project 文件夾下創建一個文件用於放置 celery 啟動的代碼,名為 celery.py,在 Project/celeryExample 文件夾下創建一個文件用於放置具體的 celery task,名為 tasks.py。則文件結構應該如下:

  • Project
    • Project
      • init.py
      • celery.py
    • celeryExample
      • init.py
      • tasks.py

為簡潔,以上省去了 Django 自動創建的文件。

把 celeryExample 添加到 Django INSTALLED_APPS 裏。添加後 Project/Projcet/settings.py 中的 INSTALLED_APPS 應該如下:

INSTALLED_APPS = [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, celeryExample]

Celery App

Django 環境下啟動 Celery 官方文檔有相應代碼,直接複製到 Project/Project/celery.py 文件內,稍加修改。此處將 os.environ.setdefault` 第二個參數修改為「Project.settings」,將 celery 應用名稱改為了 Project,在構造函數裏傳入 broker 參數設置使用 redis,並且刪除了 debug_task 方法,最後代碼如下,可直接複製。

from __future__ import absolute_import, unicode_literalsimport osfrom celery import Celery# set the default Django settings module for the celery program.os.environ.setdefault(DJANGO_SETTINGS_MODULE, Project.settings)app = Celery(Project, broker="redis://localhost")# Using a string here means the worker dont 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()

上面的代碼實例化了個 celery app,borker 參數可以設置使用的中間人,也不一定要使用redis,可以使用其它資料庫。app.autodiscover_tasks() 能夠自動在所有的 Django app 裏查找 task,能夠實現 celery app 和 task 的分離,更符合大型項目的結構。為保證 celery 能夠在 Django 啟動時啟動,把 celery.py 裏的 app import 到 Project/Project/init.py ,如下:

from .celery import app as celery_app

Celery Tasks

Celery task 為具體的非同步操作函數。在 Project/celeryExample/tasks.py 文件內進行定義。

from celery import shared_taskimport time@shared_taskdef long_time_operation(): time.sleep(10) return True

此處使用了 shared_task 裝飾器,用於設置不與具體 celery 應用綁定的 task。使用time.sleep(10) 來模擬長時操作。

有了 task 就可以使用它了,我們需要分別創建兩個頁面,一個使用非同步操作,另一個則不使用非同步操作進行比較。在 Project/celeryExample/views.py 裏添加視圖函數:

from celeryExample.tasks import long_time_operationfrom django.http import HttpResponse# Create your views here.def async_op(request): long_time_operation.delay() return HttpResponse("Async Op!")def block_op(request): long_time_operation() return HttpResponse("Finished!")

注意直接調用 long_time_operation 不會交給 celery 非同步處理,需要使用 `long_time_operation.delay() 纔可以。

為視圖函數添加相應的 url。修改 Project/Project/urls.py 如下:

from django.conf.urls import url, includefrom django.contrib import adminurlpatterns = [ url(r^admin/, admin.site.urls), url(r"^celery/", include("celeryExample.urls", namespace="celery"))]

新建 Project/celeryExample/urls.py 如下:

from django.conf.urls import urlimport celeryExample.views as viewsurlpatterns = [ url(r"async", views.async_op), url(r"block", views.block_op)]

啟動應用

首先啟動 celery,在第一層 Project 文件夾下(與 manage.py 同一目錄下)啟動終端輸入以下代碼啟動 celery。

celery -A Project worker --loglevel=info

接著可以啟動 Django server 了,新開啟一個終端輸入:

python manage.py runserver

測試

此時就一切就緒了,首先訪問127.0.0.1:8000/celery/b,瀏覽器將會一直處於載入狀態,直到10秒後長時操作完成才載入結束返回「Finished!」。再訪問127.0.0.1:8000/celery/a,由於使用了非同步處理,瀏覽器立即就得到了響應,並且在運行 celery 的終端上有相應的輸出如下:

[2017-05-08 15:49:41,244: INFO/MainProcess] Received task: celeryExample.tasks.long_time_operation[5ac8d68c-8c89-4c45-b779-66d12d285c02] [2017-05-08 15:49:51,251: INFO/PoolWorker-2] Task celeryExample.tasks.long_time_operation[5ac8d68c-8c89-4c45-b779-66d12d285c02] succeeded in 10.003452520999417s: True

是不是差異巨大!BTW: 我在我的博客系統的註冊頁面上使用了 celery 進行驗證郵箱的發送,歡迎圍觀github項目,實際部署的博客地址,也歡迎 Pull Request!


推薦閱讀:
相关文章