來源商業新知網,原標題:十面九問的逆天異步神器-celery,你瞭解多少?前端
celery是什麼,有什麼用?python
對於celery,各類文檔解釋一堆,能夠本身看下,根據平常互動,公衆號用戶小白居多,官方用到的不少名詞可能你理解起來不是那麼容易,我這裏就不照本宣科了,就以我這邊的理解簡單如下方圖示解釋下,若是有誤,歡迎指正:web
首先理解一個概念: 阻塞redis
理解阻塞,先從耗時操做講起,常見的場景好比用戶輸入、等待(sleep)這些都屬於,具體到實際項目中好比說發郵件、發短信、機器/深度學習訓練模型、自動化測試中的各類操做流程等待都會產生耗時,耗時操做一般咱們也會稱之爲阻塞,意思就是程序一行一行代碼執行,你這些耗時操做沒執行完畢,後面的代碼就不會執行,阻塞了後面的代碼執行chrome
理解了阻塞之後,就很容易引出一個問題?我若是想提升程序執行效率不讓程序阻塞,那該怎麼辦?有沒有一種方式,能在程序阻塞的時候,不影響我後面代碼的執行?數據庫
通常來講,咱們能夠用線程、進程、協程,都是能夠實現的,只不過在實際項目中,有成熟開源而且普遍應用的的東西,咱們會用框架,而不去手寫多線程、進程、協程,也不是說這些不用去學,這是編程的基本知識,也是必須掌握的,很能體現編程基本功底django
celery基本原理:編程
一、客戶端也就是python(django/flask等)發佈任務flask
二、發佈的任務存到任務隊列裏面,能夠以redis、rabbitMQ、MessageQueue、MySQL存儲,通常在django/flask程序裏redis居多後端
三、任務處理者會不斷從任務隊列裏面獲取任務執行
一、安裝django/celery庫
django==2.0.6
celery==3.1.26
django-celery==3.3.0
redis==2.10.6
都用pip安裝,我這邊這幾個版本測試沒問題,版本有些時候不兼容,若是報錯,網上找下解決
二、redis數據庫安裝
redis安裝:http://www.python88.cn/book/redis10/
注意如下幾點:
一、redis.conf改bind127.0.0.1爲bind 真實ip,這樣能夠遠程訪問
二、若是是阿里雲服務器,須要在控制檯將6379端口開放
三、redis啓動服務端:redis-server,啓動客戶端:redis-cli
三、演示代碼demo
總體流程是在前面頁面點擊表格裏面的執行,會用selenium打開瀏覽器,執行耗時操做,至關於每一個執行都是一個單獨耗時任務
四、demo前端代碼:
給按鈕綁定run_case2方法,獲取當前表格行號(映射要用selenium打開的網站連接),做爲參數傳到後端
function run_case2(obj){
row_tr = obj.parentNode.parentNode.rowIndex;//獲取當前行數
console.log(row_tr);
param = {"url":row_tr};
$.post('/web/yzm/', param, function (data) {
console.log(data.result)
})
}
五、demo後端代碼:(阻塞寫法)
看下面代碼,前端傳的行號,我這只是爲了測試傳參數,隨便構造的,分別跟3個網址進行映射,對於下面的這種寫法,就是典型的阻塞線程,webdriver在執行的時候,只有當把quit()關閉瀏覽器執行完畢時候,纔會return返回結果並在控制檯打印success,以下圖演示,我點擊的是第三個執行按鈕
from selenium import webdriver
import time
@csrf_exempt
@login_required
def yzm(request):
url_num = request.POST.get("url")
if int(url_num)==1:
url_str = "https://www.baidu.com"
elif int(url_num==2:
url_str = "http://www.python66.cn"
elif int(url_num)==3:
url_str = "http://www.python88.cn"
print(url_num,url_str)
# 下面webdriver打開網站,並休眠5秒鐘都是耗時任務
driver = webdriver.Chrome(executable_path="C:chromedriver_win32chromedriver.exe")
driver.get(url_str)
time.sleep(5)
driver.quit()
# 耗時任務執行完畢開始return
return JsonResponse({"result": "success"})
六、demo後端代碼:(celery異步)
異步: 名字雖然爲異步,你能夠理解爲同步,就是一邊作耗時操做,通常執行後面代碼,二者同時執行
文件目錄,我在項目目錄下面創建了celery_task包,建立tasks.py文件
一、建立app,表明一個celery對象,broker表明隊列,用的redis 0號數據庫
二、而後將上一步咱們selenium打開瀏覽器的方法封裝成open_url方法
三、@app.task表明定義任務,指明這個open_url方法是一個任務,能夠在視圖裏面調用發佈
from celery import Celery
from selenium import webdriver
import time
# 建立celery的應用
app = Celery("celery_task", broker="redis://47.101.203.45:6379/0")
@app.task
def open_url(url):
driver = webdriver.Chrome(executable_path="C:chromedriver_win32chromedriver.exe")
driver.get(url)
time.sleep(5)
driver.quit()
views.py視圖裏面這樣寫
一、from celery_task.tasks import open_url爲導入任務
二、open_url.delay(url_str)爲發佈任務,其中delay裏面能夠傳參數,你前端傳過來的參數views.py視圖函數接收,能夠再傳到celery任務中去
效果圖以下:當點擊執行時候,return的success很快就返回並打印了,跟我操控瀏覽器的過程沒一點牽涉,無需等待selenium,這樣就實現了非阻塞異步,完美解決了耗時問題
from celery_task.tasks import open_url
@csrf_exempt
@login_required
def yzm2(request):
url_num = request.POST.get("url")
if int(url_num)==1:
url_str = "https://www.baidu.com"
elif int(url_num)==2:
url_str = "http://www.python66.cn"
elif int(url_num)==3:
url_str = "http://www.python88.cn"
print(url_num,url_str)
open_url.delay(url_str)
return JsonResponse({"result":"success"})
七、多個任務同時執行
對於多個任務同時執行,我這裏連續點擊三個執行按鈕,立馬先打印了3個success,說明3個任務都被celery異步處理了,對於多任務的參數問題,上面也說了,咱們在delay裏面傳入參數便可,傳到定義任務的tasks.py文件裏面的對於方法中去,本例中我演示的是傳了一個url_str參數
八、啓動程序
打開兩個終端,都切換到項目目錄下面
一、先啓動celery:
celery -A celery_task.tasks worker -l info
二、再啓動django:
python manage.py runserver
本文重要的是理解原理,celery的牛逼遠不止於此,有興趣能夠看看在爬蟲、機器學習、深度學習領域的使用,會對celery的使用場景有更清晰的認識