面試必問的celery,你了解多少?


來源商業新知網,原標題:十面九問的逆天異步神器-celery,你了解多少?

 

celery是什么,有什么用?

對於celery,各種文檔解釋一堆,可以自己看下,根據日常互動,公眾號用戶小白居多,官方用到的很多名詞可能你理解起來不是那么容易,我這里就不照本宣科了,就以我這邊的理解簡單以下方圖示解釋下,如果有誤,歡迎指正:

首先理解一個概念: 阻塞

理解阻塞,先從耗時操作講起,常見的場景比如用戶輸入、等待(sleep)這些都屬於,具體到實際項目中比如說發郵件、發短信、機器/深度學習訓練模型、自動化測試中的各種操作流程等待都會產生耗時,耗時操作通常我們也會稱之為阻塞,意思就是程序一行一行代碼執行,你這些耗時操作沒執行完畢,后面的代碼就不會執行,阻塞了后面的代碼執行

理解了阻塞以后,就很容易引出一個問題?我如果想提高程序執行效率不讓程序阻塞,那該怎么辦?有沒有一種方式,能在程序阻塞的時候,不影響我后面代碼的執行?

一般來說,我們可以用線程、進程、協程,都是可以實現的,只不過在實際項目中,有成熟開源並且廣泛應用的的東西,我們會用框架,而不去手寫多線程、進程、協程,也不是說這些不用去學,這是編程的基本知識,也是必須掌握的,很能體現編程基本功底

celery基本原理:

1、客戶端也就是python(django/flask等)發布任務

2、發布的任務存到任務隊列里面,可以以redis、rabbitMQ、MessageQueue、MySQL存儲,一般在django/flask程序里redis居多

3、任務處理者會不斷從任務隊列里面獲取任務執行

知識圖譜,十面九問的逆天異步神器-celery,你了解多少?

1、安裝django/celery庫

django==2.0.6

celery==3.1.26

django-celery==3.3.0

redis==2.10.6

都用pip安裝,我這邊這幾個版本測試沒問題,版本有些時候不兼容,如果報錯,網上找下解決

2、redis數據庫安裝

redis安裝:http://www.python88.cn/book/redis10/

注意以下幾點:

1、redis.conf改bind127.0.0.1為bind 真實ip,這樣可以遠程訪問

2、如果是阿里雲服務器,需要在控制台將6379端口開放

3、redis啟動服務端:redis-server,啟動客戶端:redis-cli

3、演示代碼demo

知識圖譜,十面九問的逆天異步神器-celery,你了解多少?

整體流程是在前面頁面點擊表格里面的執行,會用selenium打開瀏覽器,執行耗時操作,相當於每個執行都是一個單獨耗時任務

4、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)
    })
}

5、demo后端代碼:(阻塞寫法)

看下面代碼,前端傳的行號,我這只是為了測試傳參數,隨便構造的,分別跟3個網址進行映射,對於下面的這種寫法,就是典型的阻塞線程,webdriver在執行的時候,只有當把quit()關閉瀏覽器執行完畢時候,才會return返回結果並在控制台打印success,如下圖演示,我點擊的是第三個執行按鈕

知識圖譜,十面九問的逆天異步神器-celery,你了解多少?

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"})

6、demo后端代碼:(celery異步)

異步: 名字雖然為異步,你可以理解為同步,就是一邊做耗時操作,一般執行后面代碼,兩者同時執行

文件目錄,我在項目目錄下面建立了celery_task包,創建tasks.py文件

知識圖譜,十面九問的逆天異步神器-celery,你了解多少?

1、創建app,代表一個celery對象,broker代表隊列,用的redis 0號數據庫

2、然后將上一步我們selenium打開瀏覽器的方法封裝成open_url方法

3、@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視圖里面這樣寫

1、from celery_task.tasks import  open_url為導入任務

2、open_url.delay(url_str)為發布任務,其中delay里面可以傳參數,你前端傳過來的參數views.py視圖函數接收,可以再傳到celery任務中去

效果圖如下:當點擊執行時候,return的success很快就返回並打印了,跟我操控瀏覽器的過程沒一點牽涉,無需等待selenium,這樣就實現了非阻塞異步,完美解決了耗時問題

知識圖譜,十面九問的逆天異步神器-celery,你了解多少?

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"})

7、多個任務同時執行

對於多個任務同時執行,我這里連續點擊三個執行按鈕,立馬先打印了3個success,說明3個任務都被celery異步處理了,對於多任務的參數問題,上面也說了,我們在delay里面傳入參數即可,傳到定義任務的tasks.py文件里面的對於方法中去,本例中我演示的是傳了一個url_str參數

知識圖譜,十面九問的逆天異步神器-celery,你了解多少?

8、啟動程序

打開兩個終端,都切換到項目目錄下面

1、先啟動celery:

celery -A celery_task.tasks worker -l info

2、再啟動django:

python manage.py runserver

本文重要的是理解原理,celery的牛逼遠不止於此,有興趣可以看看在爬蟲、機器學習、深度學習領域的使用,會對celery的使用場景有更清晰的認識


免責聲明!

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



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