天天看點

Celery+Rabbitmq實作異步任務

Celery+Rabbitmq實作異步任務

一. 安裝celery,再安裝rabbitmq或redis

pip install celery      

rabbitmq和redis安裝其中一個就可以了,celery官方文檔裡說用兩個都可以,但優先推薦rabbitmq,具體怎麼安裝可以自己找一下教程.

二. 搭建celery任務架構

  1. 在項目中适合的位置建立一個celery_tasks目錄,在這個目錄下寫celery的代碼,将celery代碼與項目

    業務邏輯代碼獨立開.當然也可以不分開,具體根據項目的代碼量和實際需要來使用.

    注意:目錄名不要直接叫celery,不要與python關鍵字,第三方子產品的名字沖突,否則導緻導包出錯

  2. ​​在建立的目錄下建立config.py​​​,​​tasks.py​​,main.py三個python檔案分别用于編寫celery的配置代碼,任務函數代碼和任務啟動代碼
# 目錄結構
- celery_tasks
    - config.py
    - main.py
    - tasks.py      

三. 編寫代碼實作異步調用任務

  1. ​​config.py​​
from celery import Celery


# 建立celery對象app,demo是對celery對象的命名,自定義,見名知義即可
# broker指定後端代理,可以使用mq或redis,主要起到任務隊列的作用
app = Celery('demo', broker='amqp://guest@localhost:5672//')
# app = Celery('demo', broker='redis://127.0.0.1:6379/15')      
  1. ​​tasks.py​​
from config import app


# 定義任務,使用celery對象.task裝飾任務,celery即可自動識别任務
@app.task(name='celery_task1_name')
def celery_task1_name(arg):
    print('編寫需要執行的任務代碼', arg)


@app.task(name='celery_task2_name')
def celery_task2_name():
    print('将需要執行的代碼導入tasks.py檔案,然後在這裡調用即可')      
  1. ​​main.py​​
from tasks import *


# 設定celery對象自動識别任務,'celery_tasks'指定tasks.py的目錄,保證程式能找到tasks.py
app.autodiscover_tasks(['celery_tasks'])      

四. 啟動celery任務

找到main.py所在目錄下,執行如下指令,如果不在此目錄,則main前要寫相對路徑,如:celery_tasks.main

celery -A main worker -l info      

-A 指定celery的啟動入口main,worker為celery執行任務的後端勞工,-l指定日志級别為info

執行成功後,celery就會啟動worker,從代理隊列中擷取任務并執行,如果任務隊列為空,則一直等待到有任務

Windows Bug:如果Celery4.0以上的版本在Windows上使用,通過上面的啟動指令啟動,在執行task.delay()時會報錯:ValueError: not enough values to unpack (expected 3, got 0)

Linux不會出現此問題,Windows才有,與“綠色線程”有關,具體閱讀eventlet相關資料

解決辦法:

  1. 安裝eventlet
pip install eventlet      
  1. 啟動worker時增加-P eventlet參數
celery -A main worker -l info -P eventlet      
from celery_tasks.main import celery_task1_name, celery_task2_name


def demo_func(a):
    # 調用格式:任務名.delay(參數)
    celery_task1_name.delay(a)
    print('celery_task1_name執行完成:{}!'.format(a))
    celery_task2_name.delay()
    print('celery_task1_name執行完成!')


demo_func('hello celery!')      

繼續閱讀