django使用celery進行耗時任務的優化


# 原創,轉載請留言聯系

在用django做項目的時候,做到注冊模塊時,需要發送短信驗證碼。本來簡簡單單的做好了,后來優化的時候發現,發送短信驗證碼的時候需要一點時間,在這個時間之內程序是阻塞的,用戶體驗太不好了。往往都是點擊獲取驗證碼后,過了幾秒鍾之后才顯示發送成功。所以想到了用celery異步任務隊列優化一下。

celery原理詳解:https://www.cnblogs.com/chichung/p/9957763.html

通過celery可以把發短信驗證碼的這部分交給其他進程來做,視圖繼續往下執行,那么當用戶點擊發送驗證碼的時候,就能馬上顯示發送成功了。

還是先看一下大體流程圖:

 

  • 步驟:

1.安裝celery

pip install celery

2.創建celery存放文件件

一般來用,celery會獨立放在項目文件下。

創建文件夾如下:

celery_tasks/
├── __init__.py
├── main.py    # 創建celery應用的地方
└── sms
    ├── __init__.py
    └── tasks.py    # 任務函數存放的地方,注意,tasks這個名字是固定的,不能改,如果改的話worker找不到!

3.創建celery應用

在main.py上:

from celery import Celery

# 第一個參數,是應用名,可以隨便寫
# 第二個參數,是中間人broker(用來保存任務)的儲存地方,保存在本機的redis的15號庫
celery_app = Celery("meiduo",broker="redis://127.0.0.1:6379/15")

4.創建celery任務

@celery.task  # 裝飾器表示把這個函數標記為celery的任務函數
def send_sms(mobile,sms_codes):
    # 下面是實現短信驗證碼發送的邏輯
    result = CCP().send_template_sms(mobile, [sms_codes, constants.SMS_CODE_REDIS_EXPIRES // 60],
                                     constants.SEND_SMS_TEMPLATE_ID)

5.設置django配置文件的路徑。

在main.py上:

# 設置django配置文件的路徑(需要在創建celery應用之前設置),設置了配置文件,celery才知道django的導包路徑是怎么樣的!
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "meiduo_mall.settings.dev")


# 第一個參數,是應用名,可以隨便寫
# 第二個參數,是中間人broker(用來保存任務)的儲存地方,保存在本機的redis的15號庫
celery_app = Celery("meiduo",broker="redis://127.0.0.1:6379/15")

6.指定用celery執行的任務函數的位置

# 設置django配置文件的路徑(需要在創建celery應用之前設置),設置了配置文件,celery才知道django的導包路徑是怎么樣的!
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "meiduo_mall.settings.dev")


# 第一個參數,是應用名,可以隨便寫
# 第二個參數,是中間人broker(用來保存任務)的儲存地方,保存在本機的redis的15號庫
celery_app = Celery("meiduo",broker="redis://127.0.0.1:6379/15")

# 指定任務函數的文件夾位置,表示從哪些位置找到任務函數。
# 查找的方法是,找到sms文件夾,然后就會自動去找tasks.py。這就是為什么task.py不能亂起名的原因。然后找到task.py里面有celery應用裝飾的函數。
celery_app.autodiscover_tasks(['celery_tasks.sms'])

7.啟動worker進程

celery -A celery應用所在py文件 worker -l info
    例: celery -A celery_tasks.main worker -l info

    服務器啟動后能夠看到如下任務,worker進程才能正常工作處理任務
    [tasks]
      . celery_tasks.sms.tasks.send_sms_code

8.通過裝飾器name參數自定義任務名(可選)

@celery_app.task(name='send_sms_code')
    def send_sms_code(mobile, sms_code):
        ...
        
    自定義完后,啟動celery工作進程在輸出信息中可以看到如下任務名
    [tasks]
      . send_sms_code

9.發送任務:  調用delay方法發送異步任務

在視圖可以調用任務函數進行發送任務了,任務會儲存在中間人broker,woker空閑時就會取出並執行。

class SmsCodesView(APIView):
    def get(self,request,mobile):
       ...
        # 發送驗證碼
        send_sms.delay(mobile,sms_codes)

       ...

10.worker執行任務

示例:

[2017-01-22 xxxx: INFO/ForkPoolWorker-2] Task         
celery_tasks.sms.tasks.send_sms_code[2f4dc753-3cd5-4eaa-994a-d944c45a857c]
succeeded in 3.2456164589966647s: None

 

  • 拓展

1.中間人broker是怎么存儲任務的?

使用json存儲:保存了任務函數標識,任務函數名,調用參數等

2.如果任務函數有返回值,應該怎么取?

(1)首先,需要有一個地方存儲任務函數的返回值。這里選擇redis的14號庫。

修改main.py

celery_app = Celery('meiduo',broker='redis://127.0.0.1:6379/15',backend='redis://127.0.0.1:6379/14')

這時候,worker執行完任務函數后,會把任務函數的返回值存儲在redis上。

(2)怎么把返回值取出來用呢?

假設發送短信這個任務函數有返回值,如果是0就是發送成功,是-1就是發送失敗。

result = send_sms.delay(mobile,sms_codes)

應該怎么拿到result的值呢?

其實,當worker執行完之后,result.ready()的值是True。未執行完是False。

當執行會之后(result.ready=True),可以用get方法取出返回值。

result.get()

 (3)怎么把配置文件獨立在一個文件里面呢?

1. 在celery_tasks包下創建配置文件 config.py, 並定義配置如下
    broker_url ='redis://127.0.0.1:6379/15'
    backend_url='redis://127.0.0.1:6379/14'
    
2. 加載配置文件
    celery_app = Celery('meiduo')  # 把配置都放到了config.py文件
    celery_app.config_from_object('celery_tasks.config')


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM