前段時(shí)間在Django Web平臺(tái)開發(fā)中椎椰,碰到一些請求執(zhí)行的任務(wù)時(shí)間較長(幾分鐘),為了加快用戶的響應(yīng)時(shí)間,因此決定采用異步任務(wù)的方式在后臺(tái)執(zhí)行這些任務(wù)复旬。在同事的指引下接觸了Celery這個(gè)異步任務(wù)隊(duì)列框架,鑒于網(wǎng)上關(guān)于Celery和Django結(jié)合的文檔較少冲泥,大部分也只是粗粗介紹了大概的流程驹碍,在實(shí)踐過程中還是遇到了不少坑,希望記錄下來幫助有需要的朋友凡恍。
一志秃、Django中的異步請求
Django Web中從一個(gè)http請求發(fā)起,到獲得響應(yīng)返回html頁面的流程大致如下:http請求發(fā)起 -- http handling(request解析) -- url mapping(url正則匹配找到對應(yīng)的View) -- 在View中進(jìn)行邏輯的處理嚼酝、數(shù)據(jù)計(jì)算(包括調(diào)用Model類進(jìn)行數(shù)據(jù)庫的增刪改查)--將數(shù)據(jù)推送到template浮还,返回對應(yīng)的template/response。
圖1\. Django架構(gòu)總覽
同步請求:所有邏輯處理闽巩、數(shù)據(jù)計(jì)算任務(wù)在View中處理完畢后返回response钧舌。在View處理任務(wù)時(shí)用戶處于等待狀態(tài)担汤,直到頁面返回結(jié)果。
異步請求:View中先返回response洼冻,再在后臺(tái)處理任務(wù)崭歧。用戶無需等待,可以繼續(xù)瀏覽網(wǎng)站撞牢。當(dāng)任務(wù)處理完成時(shí)率碾,我們可以再告知用戶。
二屋彪、關(guān)于Celery
Celery是基于Python開發(fā)的一個(gè)分布式任務(wù)隊(duì)列框架所宰,支持使用任務(wù)隊(duì)列的方式在分布的機(jī)器/進(jìn)程/線程上執(zhí)行任務(wù)調(diào)度。
圖2. Celery架構(gòu)
圖2展示的是Celery的架構(gòu)撼班,它采用典型的生產(chǎn)生-消費(fèi)者模式歧匈,主要由三部分組成:broker(消息隊(duì)列)、workers(消費(fèi)者:處理任務(wù))砰嘁、backend(存儲(chǔ)結(jié)果)件炉。實(shí)際應(yīng)用中,用戶從Web前端發(fā)起一個(gè)請求矮湘,我們只需要將請求所要處理的任務(wù)丟入任務(wù)隊(duì)列broker中斟冕,由空閑的worker去處理任務(wù)即可,處理的結(jié)果會(huì)暫存在后臺(tái)數(shù)據(jù)庫backend中缅阳。我們可以在一臺(tái)機(jī)器或多臺(tái)機(jī)器上同時(shí)起多個(gè)worker進(jìn)程來實(shí)現(xiàn)分布式地并行處理任務(wù)磕蛇。
三、Django中Celery的實(shí)現(xiàn)(本文使用Django2.0十办,celery3.1版本)
在實(shí)際使用過程中秀撇,發(fā)現(xiàn)在Celery在Django里的實(shí)現(xiàn)與其在一般.py文件中的實(shí)現(xiàn)還是有很大差別,Django有其特定的使用Celery的方式向族。這里著重介紹Celery在Django中的實(shí)現(xiàn)方法呵燕,在一般.py文件中實(shí)現(xiàn)方式可查看http://www.reibang.com/p/0f3f377384ab。
1件相、安裝依賴包
pip install django-celery
pip install celery-with-redis
2再扭、配置settings
import djcelery
# 注冊djcelery應(yīng)用
INSTALLED_APPS = (
...
'djcelery'
)
"""celery配置"""
djcelery.setup_loader()
# celery 中間人設(shè)置
BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
# celery內(nèi)容等消息的格式設(shè)置
CELERY_ACCEPT_CONTENT = ['application/json', ]
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
# 任務(wù)限制
CELERYD_CONCURRENCY = 20 # 并發(fā)worker數(shù)
CELERYD_MAX_TASKS_PER_CHILD = 100 # 每個(gè)worker最多執(zhí)行萬100個(gè)任務(wù)就會(huì)被銷 毀,可防止內(nèi)存泄露
# celery時(shí)區(qū)設(shè)置夜矗,使用settings中TIME_ZONE同樣的時(shí)區(qū)
CELERY_TIMEZONE = TIME_ZONE
3泛范、在django 根目錄下新建celery.py配置文件
from __future__ import absolute_import
from celery import Celery
import os
from django.conf import settings
project_name = os.path.split(os.path.abspath('.'))[-1]
project_settings = '%s.settings' % project_name
# 設(shè)置環(huán)境變量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', project_settings)
# 實(shí)例化Celery
app = Celery(project_name)
# 使用django的settings文件配置celery
app.config_from_object('django.conf:settings')
# Celery加載所有注冊的應(yīng)用
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
CELERY_ACCEPT_CONTENT = ['pickle']
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
4、在Django根目錄下init.py下添加
from .celery import app as celery_app
__all__ = ('celery_app',)
5紊撕、在將要使用異步加載的APP下新建tasks.py
# 從自己的項(xiàng)目中導(dǎo)入celery_app罢荡,WechatProject是我自己的項(xiàng)目名
from WechatProject import celery_app
# 將耗時(shí)的函數(shù)標(biāo)記為task
@celery_app.task
def crawl(u):
.......
其中,當(dāng)djcelery.setup_loader()運(yùn)行時(shí),Celery便會(huì)去查看INSTALLD_APPS下包含的所有app目錄中的tasks.py文件柠傍,找到標(biāo)記為task的方法麸俘,將它們注冊為celery task。
6惧笛、views調(diào)用異步任務(wù)
from .tasks import crawl
# 執(zhí)行異步任務(wù)
r = crawl.delay(u)
7从媚、啟動(dòng)Django、查看celery woker輸入日志患整、啟動(dòng)心跳執(zhí)行定時(shí)任務(wù)(每次更改定時(shí)時(shí)間拜效,都要執(zhí)行 python manage.py celery beat ,才能生效)
python manage.py runserver
python manage.py celery worker -l info
python manage.py celery beat
希望能幫助正在學(xué)習(xí)celery的你各谚,如有問題歡迎指出~本文部分參考https://www.cnblogs.com/znicy/p/5626040.html