Celery
Celery是一個功能完備即插即用的異步任務(wù)隊列系統(tǒng)杆煞。它適用于異步處理問題,當(dāng)發(fā)送郵件蘑险、或者文件上傳, 圖像處理等等一些比較耗時的操作滴肿,我們可將其異步執(zhí)行,這樣用戶不需要等待很久佃迄,提高用戶體驗泼差。
文檔:http://docs.jinkan.org/docs/celery/getting-started/index.html
Celery的特點是:
- 簡單,易于使用和維護(hù)呵俏,有豐富的文檔堆缘。
- 高效,單個celery進(jìn)程每分鐘可以處理數(shù)百萬個任務(wù)普碎。
- 靈活吼肥,celery中幾乎每個部分都可以自定義擴(kuò)展。
任務(wù)隊列是一種跨線程麻车、跨機(jī)器工作的一種機(jī)制.
任務(wù)隊列中包含稱作任務(wù)的工作單元缀皱。有專門的工作進(jìn)程持續(xù)不斷的監(jiān)視任務(wù)隊列,并從中獲得新的任務(wù)并處理.
celery通過消息進(jìn)行通信动猬,通常使用一個叫Broker(中間人)來協(xié)client(任務(wù)的發(fā)出者)和worker(任務(wù)的處理者). clients發(fā)出消息到隊列中啤斗,broker將隊列中的信息派發(fā)給worker來處理。
Celery的架構(gòu)
Celery的架構(gòu)由三部分組成赁咙,消息隊列(message broker)钮莲,任務(wù)執(zhí)行單元(worker)和任務(wù)執(zhí)行結(jié)果存儲(task result store)組成。
一個celery系統(tǒng)可以包含很多的worker和broker
Celery本身不提供消息隊列功能彼水,但是可以很方便地和第三方提供的消息中間件進(jìn)行集成崔拥,包括RabbitMQ,Redis,MongoDB等
安裝
pip install -U celery
也可從官方直接下載安裝包:https://pypi.python.org/pypi/celery/
tar xvfz celery-0.0.0.tar.gz
cd celery-0.0.0
python setup.py build
python setup.py install
使用
使用celery第一件要做的最為重要的事情是需要先創(chuàng)建一個Celery實例,一般叫做celery應(yīng)用猿涨,或者更簡單直接叫做一個app握童。app應(yīng)用是使用celery所有功能的入口姆怪,比如創(chuàng)建任務(wù)叛赚,管理任務(wù)等,在使用celery的時候稽揭,app必須能夠被其他的模塊導(dǎo)入俺附。
一般celery任務(wù)目錄直接放在項目的根目錄下即可,路徑:
api/
├── mycelery/
├── config.py # 配置文件
├── __init__.py
├── main.py # 主程序
└── sms/ # 一個目錄可以放置多個任務(wù),該目錄下存放當(dāng)前任務(wù)執(zhí)行時需要的模塊或依賴
└── tasks.py # 任務(wù)的文件溪掀,名稱必須是這個!!!
main.py事镣,代碼:
# 主程序
from celery import Celery
# 創(chuàng)建celery實例對象
app = Celery("xxx")
# 通過app對象加載配置
app.config_from_object("mycelery.config")
# 自動搜索并加載任務(wù)
# 參數(shù)必須必須是一個列表,里面的每一個任務(wù)都是任務(wù)的路徑名稱
# app.autodiscover_tasks(["任務(wù)1","任務(wù)2",....])
app.autodiscover_tasks(["mycelery.sms","mycelery.cache"])
# 啟動Celery的命令
# 強(qiáng)烈建議切換目錄到項目的根目錄下啟動celery!!
# celery -A mycelery.main worker --loglevel=info
配置文件config.py揪胃,代碼:
# 任務(wù)隊列的鏈接地址
broker_url = 'redis://127.0.0.1:6379/15'
# 結(jié)果隊列的鏈接地址
result_backend = 'redis://127.0.0.1:6379/14'
創(chuàng)建一個任務(wù)文件sms/tasks.py璃哟,并創(chuàng)建任務(wù)氛琢,代碼:
# celery的任務(wù)必須寫在tasks.py的文件中,別的文件名稱不識別!!!
from mycelery.main import app
@app.task # name表示設(shè)置任務(wù)的名稱随闪,如果不填寫阳似,則默認(rèn)使用函數(shù)名做為任務(wù)名
def send_sms():
print("發(fā)送短信!!!")
@app.task(name="send_sms2") # name表示設(shè)置任務(wù)的名稱,如果不填寫铐伴,則默認(rèn)使用函數(shù)名做為任務(wù)名
def send_sms2():
print("發(fā)送短信任務(wù)2!!!")
接下來撮奏,運(yùn)行celery,效果如下:
在程序中調(diào)用上面的異步任務(wù)当宴,拿django進(jìn)行舉例:
# 調(diào)用celery執(zhí)行異步任務(wù)
from my_celery.sms.tasks import send_sms
send_sms.delay(mobile)
其他參考文檔:
http://docs.celeryproject.org/en/latest/getting-started/introduction.html
https://github.com/celery/celery/tree/master/examples/django/
http://www.reibang.com/p/1840035cb510
https://flower.readthedocs.io/en/latest/screenshots.html
把celery和django組合起來一起使用畜吊。
django和celery進(jìn)行組合
在main.py主程序中對django的配置文件進(jìn)行加載
# 主程序
import os
from celery import Celery
# 創(chuàng)建celery實例對象
app = Celery("xxx")
# 把celery和django進(jìn)行組合,識別和加載django的配置文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'api.settings.dev')
# 對django框架執(zhí)行初始化
import django
django.setup()
# 通過app對象加載配置
app.config_from_object("mycelery.config")
# 加載任務(wù)
# 參數(shù)必須必須是一個列表户矢,里面的每一個任務(wù)都是任務(wù)的路徑名稱
# app.autodiscover_tasks(["任務(wù)1","任務(wù)2"])
app.autodiscover_tasks(["mycelery.sms","mycelery.cache"])
# 啟動Celery的命令
# 強(qiáng)烈建議切換目錄到mycelery根目錄下啟動
# celery -A mycelery.main worker --loglevel=info
在需要使用django配置的任務(wù)中玲献,直接加載配置,把注冊的短信發(fā)送功能梯浪,整合成一個任務(wù)函數(shù)青自,代碼:
from my_celery.main import app
from .yuntongxun.sms import CCP
from luffyapi.settings import constants
import logging
log = logging.getLogger("django")
# @app.task(name="send_sms")
# def send_sms(mobile):
# print("發(fā)送短信給%s的異步任務(wù)執(zhí)行了" % mobile)
# return "任務(wù)結(jié)果!"
@app.task(name="send_sms")
def send_sms(mobile, sms_code):
"""異步發(fā)送短信"""
ccp = CCP()
try:
result = ccp.send_template_sms(mobile, [sms_code, constants.SMS_EXPIRE_TIME//60 ], constants.SMS_TEMPLATE_ID)
return result
except:
log.error("發(fā)送短信驗證碼失斍ぁ延窜!手機(jī)號:%s" % mobile)
在這個任務(wù)中,需要加載短信發(fā)送的sdk和相關(guān)的配置常量抹锄,所以可以直接把django中的短信發(fā)送模塊和相關(guān)的常量配置文件直接剪切到當(dāng)前sms任務(wù)目錄中
mycelery/
├── config.py
├── __init__.py
├── main.py
└── sms/
├── constant.py
├── __init__.py
├── tasks.py
└── yuntongxun
├── CCPRestSDK.py
├── __init__.py
├── sms.py
└── xmltojson.py
再次啟動項目即可逆瑞。
最終在django里面調(diào)用Celery來異步執(zhí)行任務(wù)。需要完成2個步驟:
# 1. 聲明一個和celery一模一樣的任務(wù)函數(shù)伙单,導(dǎo)包來解決
from mycelery.sms.tasks import send_sms
# 2. 調(diào)用任務(wù)函數(shù)获高,發(fā)布任務(wù)
send_sms.delay(mobile,code)
# send_sms.delay() 如果調(diào)用的任務(wù)函數(shù)沒有參數(shù),則不需要填寫任何內(nèi)容