Django初步使用Celery處理耗時(shí)任務(wù)和定時(shí)任務(wù)問(wèn)題
Celery是Python開(kāi)發(fā)分布式任務(wù)列隊(duì)的處理庫(kù)。可以異步分布式地異步處理任務(wù),也可定時(shí)執(zhí)行任務(wù)等等。
通常我們可以使用celery在Django執(zhí)行一些比較耗時(shí)的任務(wù)(例如發(fā)郵件)和后臺(tái)任務(wù)(例如爬蟲(chóng)和更新服務(wù)器緩存)。
在Django中使用有兩種方式:
- 1)使用django-celery應(yīng)用
- 2)直接使用Celery
1、Celery方式的選擇
這里Celery的中間人,采用Redis。也可以用Django自身的mongodb等。Celery的中間人你可以理解為在Celery執(zhí)行過(guò)程中的數(shù)據(jù)支持。保存列隊(duì)記錄、執(zhí)行記錄等等。
需要安裝celery-with-redis,執(zhí)行命令
pip?install?celery-with-redis
該命令會(huì)自動(dòng)安裝redis(python庫(kù)操作redis的庫(kù))、celery、kombu、billiard、amqp、vine和celery-with-redis相關(guān)庫(kù)。
注意,這里pip安裝的redis是python操作redis的庫(kù),非redis數(shù)據(jù)庫(kù)。
redis數(shù)據(jù)庫(kù)需要獨(dú)立安裝,在cmd里輸入 pip3 install redis
先說(shuō)說(shuō)django-celery的方式吧。這種方式就是通過(guò)manage.py啟動(dòng)celery。通常先被提到的方案是不會(huì)采用。用pip安裝django-celery,在settings引用djcelery應(yīng)用。
再更新數(shù)據(jù)庫(kù):
python manage.py makemigrations djcelery python manage.py migrate djcelery
查看數(shù)據(jù)庫(kù),會(huì)發(fā)現(xiàn)多了很多相關(guān)的表,顯得十分多余了就。
djcelery還有個(gè)用途是在admin后臺(tái)動(dòng)態(tài)添加定時(shí)任務(wù)。這個(gè)功能也是比較雞肋,維護(hù)不方便而且可能造成各種不可預(yù)知的問(wèn)題。
所以建議直接使用Celery管理Django中的任務(wù)(第二種方式)。這種方式也是Celery官網(wǎng)推薦的方式。
2、Django簡(jiǎn)單項(xiàng)目準(zhǔn)備
這里我也簡(jiǎn)單做一個(gè)示例。
首先,確保celery和redis已經(jīng)安裝好了,并且已經(jīng)啟動(dòng)了Redis服務(wù)。
另外,有個(gè)已經(jīng)搭建好了Django項(xiàng)目。
作為示例,簡(jiǎn)單project和簡(jiǎn)單app如下:

左邊側(cè)邊欄是該django的目錄結(jié)構(gòu),右邊是myapp中的Blog模型。
再進(jìn)入后臺(tái)隨便加了兩條數(shù)據(jù):

為了測(cè)試,一切從簡(jiǎn)。views.py寫(xiě)了一個(gè)響應(yīng)方法:
#views.py
from django.shortcuts import render
from django.http import HttpResponse
from models import Blog
import json
def home(request):
data = list(Blog.objects.values('caption'))
return HttpResponse(json.dumps(data), content_type = 'application/json')django項(xiàng)目的urls.py加了一條首頁(yè)的url路由設(shè)置:
#urls.py
from django.conf.urls import url
from django.contrib import admin
from myapp.
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', 'myapp.views.home', name='home')
]運(yùn)行django項(xiàng)目:
python?manage.py?runserver
打開(kāi)http://localhost:8000/,如下效果:

3、Django加入Celery
現(xiàn)打開(kāi)首頁(yè)要執(zhí)行一個(gè)收集訪(fǎng)客數(shù)據(jù),發(fā)送郵件等操作。這是一個(gè)耗時(shí)任務(wù),若放在home處理方法中執(zhí)行,用戶(hù)打開(kāi)首頁(yè)會(huì)很慢。用戶(hù)體驗(yàn)不好,很可能不會(huì)等到頁(yè)面打開(kāi)。
通常這個(gè)耗時(shí)任務(wù)可以多線(xiàn)程處理或者異步處理。我們模擬一個(gè)耗時(shí)任務(wù),丟給Celery異步處理。
先模擬耗時(shí)任務(wù),打開(kāi)views.py,修改如下:
#views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Blog
import json
import time
def sendmail(email):
print('start send email to %s' % email)
time.sleep(5) #休息5秒
print('success')
return True
def home(request):
#耗時(shí)任務(wù),發(fā)送郵件
sendmail('test@test.com')
#其他行為
data = list(Blog.objects.values('caption'))
return HttpResponse(json.dumps(data), content_type = 'application/json')如此一來(lái),至少需要再多等待5秒,才可以打開(kāi)網(wǎng)頁(yè)。
打開(kāi)settings.py所在的文件夾,新建celery.py文件。
加入如下代碼(注意,因?yàn)閏elery-with-django版本限制,我安裝的celery版本為3.1.25??赡躢elery4.x的版本代碼不同):
#celery.py
from __future__ import absolute_import, unicode_literals
from celery import Celery
from django.conf import settings
import os
#獲取當(dāng)前文件夾名,即為該Django的項(xiàng)目名
project_name = os.path.split(os.path.abspath('.'))[-1]
project_settings = '{}.settings'.format(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加載所有注冊(cè)的應(yīng)用
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)這個(gè)文件還沒(méi)被加載,接著打開(kāi)settings.py同個(gè)目錄下的__init__.py文件。讓運(yùn)行該Django項(xiàng)目的時(shí)候,加載該文件配置Celery。
修改代碼如下:
#__init__.py from __future__ import absolute_import, unicode_literals #引入celery實(shí)例對(duì)象 from .celery import app as celery_app
還需在settings.py中設(shè)置celery,尤其是中間人的設(shè)置。若不設(shè)置中間人,會(huì)提示無(wú)法連接中間人的錯(cuò)誤。
在settings.py文件中添加如下設(shè)置:
#celery settings #celery中間人 redis://redis服務(wù)所在的ip地址:端口/數(shù)據(jù)庫(kù)號(hào) BROKER_URL = 'redis://localhost:6379/0' #celery結(jié)果返回,可用于跟蹤結(jié)果 CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' #celery內(nèi)容等消息的格式設(shè)置 CELERY_ACCEPT_CONTENT = ['application/json',] CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json' #celery時(shí)區(qū)設(shè)置,使用settings中TIME_ZONE同樣的時(shí)區(qū) CELERY_TIMEZONE = TIME_ZONE
4、把耗時(shí)任務(wù)丟給celery處理
上面views.py中有個(gè)耗時(shí)任務(wù)sendmail。在myapp應(yīng)用中新建文件tasks.py,將sendmail方法剪切到該文件中并用定義為celery任務(wù)。
tasks.py文件如下代碼:
#tasks.py
from celery.decorators import task
import time
@task
def sendmail(email):
print('start send email to %s' % email)
time.sleep(5) #休息5秒
print('success')
return True在原有的方法上加上celery裝飾器task(或者也可以通過(guò)前面添加的celery_app給sendmail方法加裝飾器):
#tasks.py
#myproject是當(dāng)前django的項(xiàng)目名
from myproject import celery_app
import time
@celery_app.task
def sendmail(email):
print('start send email to %s' % email)
time.sleep(5) #休息5秒
print('success')
return True另外原先的views.py修改如下:
#views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Blog
from .tasks import sendmail #引用tasks.py文件的中sendmail方法
import json
def home(request):
#耗時(shí)任務(wù),發(fā)送郵件(用delay執(zhí)行方法)
sendmail.delay('test@test.com')
#其他行為
data = list(Blog.objects.values('caption'))
return HttpResponse(json.dumps(data), content_type = 'application/json')5、本地啟動(dòng)celery并測(cè)試
啟動(dòng)celery之前,確保已經(jīng)安裝redis和啟動(dòng)redis服務(wù)。
本地開(kāi)發(fā)環(huán)境運(yùn)行redis-cli看是否可以正常連接,若不行,再手工執(zhí)行redis-server命令并保持窗口即可。

接著,啟動(dòng)celery worker。這個(gè)worker是用于異步執(zhí)行任務(wù)的“工作者”。
進(jìn)入manage.py文件所在的目錄,執(zhí)行如下命令:
Celery?-A?myproject?worker?-l?info
出現(xiàn)如下窗口和消息,則正常執(zhí)行。

celery worker會(huì)掃描django項(xiàng)目中有哪些task任務(wù),并加入進(jìn)來(lái)。見(jiàn)上圖的藍(lán)色字下[tasks]字樣。
最后,再啟動(dòng)django服務(wù)器。這個(gè)大家熟悉的python manage.py runserver。
打開(kāi)首頁(yè),可以發(fā)現(xiàn)沒(méi)有5秒等待立即得到首頁(yè)內(nèi)容。查看celery worker,可看到執(zhí)行sendmail方法的消息。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- django中celery的定時(shí)任務(wù)使用
- django-celery-beat搭建定時(shí)任務(wù)的實(shí)現(xiàn)
- 關(guān)于Django使用 django-celery-beat動(dòng)態(tài)添加定時(shí)任務(wù)的方法
- Django+Celery實(shí)現(xiàn)定時(shí)任務(wù)的示例
- Django+Celery實(shí)現(xiàn)動(dòng)態(tài)配置定時(shí)任務(wù)的方法示例
- Django實(shí)現(xiàn)celery定時(shí)任務(wù)過(guò)程解析
- Django中使用Celery執(zhí)行定時(shí)任務(wù)問(wèn)題
相關(guān)文章
Python中22個(gè)萬(wàn)用公式的小結(jié)
在大家的日常python程序的編寫(xiě)過(guò)程中,都會(huì)有自己解決某個(gè)問(wèn)題的解決辦法,或者是在程序的調(diào)試過(guò)程中,用來(lái)幫助調(diào)試的程序公式,本文總結(jié)了22個(gè)萬(wàn)用公式,感興趣的可以了解一下2021-07-07
Python實(shí)現(xiàn)解析Bit Torrent種子文件內(nèi)容的方法
這篇文章主要介紹了Python實(shí)現(xiàn)解析Bit Torrent種子文件內(nèi)容的方法,結(jié)合實(shí)例形式分析了Python針對(duì)Torrent文件的讀取與解析相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2017-08-08
Xadmin+rules實(shí)現(xiàn)多選行權(quán)限方式(級(jí)聯(lián)效果)
這篇文章主要介紹了Xadmin+rules實(shí)現(xiàn)多選行權(quán)限方式(級(jí)聯(lián)效果),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04
YOLOv5車(chē)牌識(shí)別實(shí)戰(zhàn)教程(五)字符分割與識(shí)別
這篇文章主要介紹了YOLOv5車(chē)牌識(shí)別實(shí)戰(zhàn)教程(五)字符分割與識(shí)別,在這個(gè)教程中,我們將一步步教你如何使用YOLOv5進(jìn)行車(chē)牌識(shí)別,幫助你快速掌握YOLOv5車(chē)牌識(shí)別技能,需要的朋友可以參考下2023-04-04
python 利用turtle模塊畫(huà)出沒(méi)有角的方格
今天小編就為大家分享一篇python 利用turtle模塊畫(huà)出沒(méi)有角的方格,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11

