django通過(guò)celery添加異步任務(wù)

異步任務(wù)的重要性

大家在做web項(xiàng)目的時(shí)候經(jīng)常會(huì)遇到一些耗時(shí)的操作, 比如: 發(fā)送郵件、發(fā)送短信、生成pdf。這些操作在某些情況下需要立即返回結(jié)果給用戶,但是可以在后臺(tái)異步執(zhí)行。

比如用戶郵箱注冊(cè)的時(shí)候, 在發(fā)送郵件的時(shí)候可以先把”已經(jīng)發(fā)送激活郵件到郵箱”返回給用戶, 同時(shí)把郵件發(fā)送任務(wù)提交到異步處理線程中。

現(xiàn)在介紹一款python寫的專門用于處理異步任務(wù)的框架–celery。當(dāng)然celery能完成的功能遠(yuǎn)不止異步任務(wù), 還有一個(gè)很常用的功能–定時(shí)任務(wù)

celery的功能還包括:定義工作流、監(jiān)控、任務(wù)流控制、資源泄露保護(hù)以及自定義用戶組件等。

celery介紹

說(shuō)明:
    最新版本的celery支持的python版本必須大于2.7.6,
    如果是python2.7.6及以下版本的時(shí)候import celery是會(huì)報(bào)錯(cuò)滴。

celery是通過(guò)將代碼序列然后傳輸?shù)街虚g通信組件,這些組件可以采用任何方式實(shí)現(xiàn), 這里最常用的兩種是rabbitmq和redis, 然后celery的后臺(tái)線程不停的從rabbitmq或者redis中讀取這些任務(wù)并執(zhí)行然后返回結(jié)果到這些組件,這樣就實(shí)現(xiàn)了一個(gè)異步的功能。

Celery 用redis或者rabbitmq做消息通信,這里redis或者rabbitmq被稱為中間人(Broker)Celery 系統(tǒng)可包含多個(gè)線程和中間人,以此獲得高可用性和橫向擴(kuò)展能力。

Celery 雖然是用 Python 編寫的,但協(xié)議可以用任何語(yǔ)言實(shí)現(xiàn)。迄今,已有 Ruby 實(shí)現(xiàn)的 RCelery 、node.js 實(shí)現(xiàn)的 node-celery 以及一個(gè) PHP 客戶端 ,語(yǔ)言互通也可以通過(guò) using webhooks 實(shí)現(xiàn)。

django 介紹

django作為python最主流也是資格最老的的web開(kāi)發(fā)系統(tǒng),是一個(gè)全棧的開(kāi)發(fā)框架,幾乎web開(kāi)發(fā)系統(tǒng)中會(huì)用到的所有功能django都有,即使沒(méi)有也可以在網(wǎng)站找到對(duì)應(yīng)的開(kāi)源解決方案,在stackoverflow上的問(wèn)答也是最多的。基本上學(xué)習(xí)懂了django以后學(xué)習(xí)其他如flask、tornado都會(huì)覺(jué)得手到擒來(lái)。

本文中我們就介紹一下如何將celery集成到django中來(lái)完成django耗時(shí)任務(wù)的異步執(zhí)行和定時(shí)任務(wù)計(jì)劃。

我們將采用redis來(lái)做為中間人

celery 安裝和使用

celery安裝

pip install -U celery[redis]

該命令會(huì)安裝celery以及redis開(kāi)發(fā)相關(guān)所有的依賴包。安裝完成我們可以看到:

安裝celery后的截圖.png

這里我們可以看到安裝了billiard、pytz、vine、amqp、redis、celery等

redis-server安裝

既然是用redis做中間人,當(dāng)然需要安裝redis了、我們直接運(yùn)行:

sudo apt-getin install redis-server

運(yùn)行成功以后可以,redis-server直接就作為服務(wù)啟動(dòng)了, 我們可以通過(guò):

ps aux|grep redis

命令來(lái)查看redis是否啟動(dòng)如下圖:


查看redis服務(wù)器啟動(dòng)情況.png

這里我們可以看到redis已經(jīng)在6379端口監(jiān)聽(tīng)了

啟動(dòng)celery的worker

前面介紹了celery的處理流程, 既然我們已經(jīng)啟動(dòng)了redis, 當(dāng)然我們需要啟動(dòng)一個(gè)隨時(shí)監(jiān)聽(tīng)異步處理函數(shù)的worker了。 這里我們直接啟動(dòng)celery的worker就行了

首先我們來(lái)新建一個(gè)tasks.py 文件, 內(nèi)容如下:

from celery import Celery

app = Celery('hello', broker='redis://localhost:6379/0')

@app.task
def hello():
    return 'hello world'

然后我們?cè)试S下面的命令啟動(dòng)celery的worker

celery -A tasks worker --loglevel=info

注:

這里tasks表示的是上面創(chuàng)建的文件的名字, 比如如果我們的py文件為tasks.py, 則直接 celery -A tasks worker --loglevel=info。 如果我們的py文件為celery-tasks這命令應(yīng)該修改為:
celery -A celery-tasks worker --loglevel=info

啟動(dòng)后我們就可以看到celery已經(jīng)啟動(dòng)了線程時(shí)刻監(jiān)聽(tīng)redis中的異步函數(shù),如下:


celery啟動(dòng)截圖.png

接下來(lái)我們分析一下上面的tasks.py文件:

    1\. 首先直接初始化Celery對(duì)象, 并指明使用的redis的連接地址
    2\. 直接用celery對(duì)象的task裝飾任何我們需要異步的函數(shù)
簡(jiǎn)單兩步就完成了celery的異步函數(shù)

直接執(zhí)行異步函數(shù)

這一步里面我們直接新建test.py文件, 內(nèi)容如下:

from tasks import add

add.delay(1,2)

注意這里對(duì)add函數(shù)的調(diào)用采用的是delay函數(shù)而不是直接采用add(1,2),因?yàn)檫@樣調(diào)用就和普通函數(shù)調(diào)用沒(méi)有區(qū)別了。所以這里一定要注意。運(yùn)行test.py文件后我們可以看到celery的輸出:

celery接收到celery的截圖.png

在最后面我們可以清楚的看到調(diào)用了add函數(shù), add函數(shù)的執(zhí)行結(jié)果會(huì)返回到redis中
這里delay函數(shù)是將函數(shù)執(zhí)行異步放入到redis中交給celery執(zhí)行, 這樣delay之后就會(huì)有個(gè)問(wèn)題就是如果我們需要理解得到結(jié)果怎么辦呢?

我們可以直接調(diào)用:

add.delay(1,2).get()

這樣就變成同步的了,等到返回結(jié)果才會(huì)去執(zhí)行下一步

celery添加異步任務(wù)

celery的使用非常簡(jiǎn)單

這里我們可以看到需要將一個(gè)函數(shù)變?yōu)楫惒胶瘮?shù)非常簡(jiǎn)單, 只需要添加@app.task裝飾器就夠了。 是不是非常簡(jiǎn)單啊。

  1. 配置celery連接redis

    app.conf.result_backend = ‘redis://localhost:6379/0

  2. 配置任務(wù)執(zhí)行結(jié)果保存地址

    app.conf.result_backend = ‘redis://localhost:6379/0

    前面我們講到過(guò)celery是從中間人取出函數(shù)并執(zhí)行,但是保存結(jié)果也需要保存到中間人, 這里實(shí)際上取任務(wù)的地方和保存結(jié)果的中間人實(shí)際上可以不一樣, 所有這里就提供了中間結(jié)果執(zhí)行的保存地址

集成celery到django中

這里以我的一門django搭建在線教育平臺(tái)的課程為例來(lái)講解,大家如果有興趣可以去關(guān)注一下,課程強(qiáng)力django+殺手級(jí)xadmin

首先我們來(lái)看一下完整的系統(tǒng)結(jié)構(gòu)圖:


系統(tǒng)結(jié)構(gòu).png

1.修改django項(xiàng)目的MxOnline/settings.py文件, 加上:

###配置Broker
BROKER_URL = 'redis://127.0.0.1:6379/0'
BROKER_TRANSPORT = 'redis'

2.在MxOline下面新建celery.py文件

from __future__ import absolute_import

import os
import django

from celery import Celery
from django.conf import settings

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MxOnline.settings')
django.setup()

app = Celery('MxOnline')

app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

結(jié)構(gòu)如圖所示:


添加celerypy文件后.png

3.在對(duì)應(yīng)的app下面新建tasks.py文件, 這里我們?cè)趗sers這個(gè)app下面新建, 如圖所示:

文件源碼如下:

from MxOnline.celery import app

@app.task
def send_register_email(email, send_type="register"):
    email_record = EmailVerifyRecord()
    if send_type == "update_email":
        code = random_str(4)
    else:
        code = random_str(16)
    email_record.code = code
    email_record.email = email
    email_record.send_type = send_type
    email_record.save()

    email_title = ""
    email_body = ""

    if send_type == "register":
        email_title = "慕學(xué)在線網(wǎng)注冊(cè)激活鏈接"
        email_body = "請(qǐng)點(diǎn)擊下面的鏈接激活你的賬號(hào): http://www.imooc.com/active/{0}".format(code)

        send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
        if send_status:
            pass
    elif send_type == "forget":
        email_title = "慕學(xué)在線網(wǎng)注冊(cè)密碼重置鏈接"
        email_body = "請(qǐng)點(diǎn)擊下面的鏈接重置密碼: http://www.imooc.com/reset/{0}".format(code)

        send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
        if send_status:
            pass
    elif send_type == "update_email":
        email_title = "慕學(xué)在線郵箱修改驗(yàn)證碼"
        email_body = "你的郵箱驗(yàn)證碼為: {0}".format(code)

        send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
        if send_status:
            pass

4\. 編輯views.py文件完成郵件發(fā)送異步調(diào)用:

    #coding:utf-8
    from django.shortcuts import render
    from django.http import HttpResponse

    from .tasks import send_register_email

    def index(request):
        send_register_email.delay()
        return HttpResponse(u"郵件發(fā)送成功, 請(qǐng)查收")

5\. 進(jìn)入MxOnline目錄運(yùn)行:
    celery -A demo worker -l debug

    以此來(lái)啟動(dòng)celery的worker服務(wù)

關(guān)于django是如何實(shí)現(xiàn)郵件發(fā)送以及如何配置郵件的發(fā)送方配置,在課程強(qiáng)力django+殺手級(jí)xadmin中我會(huì)詳細(xì)講解,另外,課程中還會(huì)講解django實(shí)現(xiàn)cookie和session的登錄原理,當(dāng)然django的強(qiáng)大絕不止于此,尤其是結(jié)合x(chóng)admin,你幾乎可以做到以最快的速度搭建完整的前后臺(tái),如果你想全面掌握django,謀求一份python web 開(kāi)發(fā)的工作,那就跟我一起來(lái)做一次實(shí)戰(zhàn):用django開(kāi)發(fā)一個(gè)完整的在線教育網(wǎng)站,在實(shí)戰(zhàn)中學(xué)習(xí)是掌握技術(shù)的捷徑,你不僅會(huì)理解真實(shí)開(kāi)發(fā)與純理論的差別,更會(huì)了解如何避免開(kāi)發(fā)中的“坑”,同時(shí),這套完整的在線教育網(wǎng)站的全套代碼都會(huì)開(kāi)放給你,你甚至可以直接拿來(lái)用在工作中,所以如果這些是你想要的,那么我在慕課網(wǎng)等著你

至此,大功告成了!我們可以在我們定義的任何apps中添加tasks來(lái)定義需要的異步任務(wù)。

轉(zhuǎn)自bobby博客,自用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容