當前位置:
首頁 > 知識 > Django 使用 Celery 實現非同步任務

Django 使用 Celery 實現非同步任務

(點擊

上方藍字

,快速關注我們)




來源:伯樂在線 - 王海波


如有好文章投稿,請點擊 → 這裡了解詳情




對於網站來說,給用戶一個較好的體驗是很重要的事情,其中最重要的指標就是網站的瀏覽速度。因此服務端要從各個方面對網站性能進行優化,比如可採用CDN載入一些公共靜態文件,如js和css;合併css或者js從而減少靜態文件的請求等等…..還有一種方法是將一些不需要立即返回給用戶,可以非同步執行的任務交給後台處理,以防網路阻塞,減小響應時間。看了the5fire的博客之後我受到了啟發,決定從這方面進行改進。




我採用celery實現後台非同步執行的需求。對於celery,先看一下網上給的celery的定義和用途:




Celery

is

a

simple

,

flexible

,

and

reliable distributed system

to

process vast amounts of

messages

,

while

providing operations with the tools required

to

maintain

such

a

system

.


 


It

s

a

task queue with focus on

real

-

time

processing

,

while

also supporting task

scheduling

.


 


Celery

has

a

large

and

diverse community of users

and

contributors

,

you should come join us on IRC

or

our

mailing

-

list

.




上面的英文還是比較好理解的,簡而言之,就是一個專註於實時處理和任務調度的分散式隊列。




我買了一本《Python Web開發實戰》,那裡面也介紹了celery。說了使用celery的常見場景:






  1. Web應用。當用戶觸發一個動作需要較長時間來執行完成時,可以把它作為任務交給celery非同步執行,執行完再返回給用戶。這點和你在前端使用ajax實現非同步載入有異曲同工之妙。



  2. 定時任務。假設有多台伺服器,多個任務,定時任務的管理是很困難的,你要在不同電腦上寫不同的crontab,而且還不好管理。Celery可以幫助我們快速在不同的機器設定不同任務。



  3. 其他可以非同步執行的任務。比如發送簡訊,郵件,推送消息,清理/設置緩存等。這點還是比較有用的。




綜上所述,第1點和第3點的用途是我考慮celery的原因。目前,考慮在Django中實現兩個功能:






  • 文章閱讀量的統計



  • 發送郵件




關於文章閱讀量的統計,我之前的做法就是在用戶每一次訪問文章的時候,都會同步執行一遍+1的函數,現在打算用非同步執行的方式。




下面介紹在Django中的使用方法:




1、環境準備




安裝celery,rabbitmq,django-celery.




2、啟動消息中間件rabbitmq。




用它的原因是celery官方推薦的就是它,也可以用Redis等,但Redis會因為斷電的原因造成數據全部丟失等問題。




讓其在後台運行:





sudo rabbitmq-server -detached




3、在Django中配置(源代碼)




項目代碼結構





dailyblog


 


    

├──

blog


  

├──

models

.

py


  

├──

serializer

.

py


  

├──

tasks

.

py


  

├──

urls

.

py


  

├──

views

.

py


├──

config

.

yaml


├──

dailyblog


  

├──

celery

.

py


  

├──

__init__

.

py


  

├──

__init__

.

pyc


  

├──

settings

.

py


  

├──

urls

.

py


  

├──

wsgi

.

py




對於celery的配置,需要編寫幾個文件:





  

1

dailyblog

/

celery

.

py


 


  

2

dailyblog

/

settings

.

py


 


  

3

blog

/

tasks

.

py


 


  

4

dailyblog

/

__init__

.

py




1、dailyblog/celery.py




本模塊主要是創建了celery應用,配置來自django的settings文件。





from __future__ import

absolute_import

,

unicode_literals

#目的是拒絕隱士引入,celery.py和celery衝突。


import os


from celery import Celery


from

django

.

conf import settings


 


 


os

.

environ

.

setdefault

(

"DJANGO_SETTINGS_MODULE"

,

"dailyblog.settings"

)


 


#創建celery應用


app

=

Celery

(

"dailyblog"

)


#You can pass the object directly here, but using a string is better since then the worker doesn』t have to serialize the object.


app

.

config_from_object

(

"django.conf:settings"

)


#如果在工程的應用中創建了tasks.py模塊,那麼Celery應用就會自動去檢索創建的任務。比如你添加了一個任務,在django中會實時地檢索出來。


app

.

autodiscover_tasks

(

lambda

:

settings

.

INSTALLED_APPS

)




關於config_from_object,我對於如何載入配置文件還是比較感興趣的,於是研究了一下源碼,具體可以見:「celery載入配置文件」。




2、settings.py




配置celery,





import djcelery


djcelery

.

setup_loader

()


 


 


#末尾添加


CELERYBEAT_SCHEDULER

=

djcelery

.

schedulers

.

DatabaseScheduler

  

# 這是使用了django-celery默認的資料庫調度模型,任務執行周期都被存在你指定的orm資料庫中


 


#INstalled_apps


    

INSTALLED_APPS

=

(


    

django

.

contrib

.

admin

,


    

django

.

contrib

.

auth

,


    

django

.

contrib

.

contenttypes

,


    

django

.

contrib

.

sessions

,


    

django

.

contrib

.

messages

,


    

django

.

contrib

.

staticfiles

,


    

djcelery

,

    

#### 這裡增加了djcelery 也就是為了在django admin裡面可一直接配置和查看celery


    

blog

,

    

###


)




setup_loader目的是設定celery的載入器,源碼:





  

def setup_loader

()

:  

# noqa


    

os

.

environ

.

setdefault

(


        

b

"CELERY_LOADER"

,

b

"djcelery.loaders.DjangoLoader"

,


    

)




3、dailyblog/init.py





from __future__ import

absolute_import


 


# This will make sure the app is always imported when


# Django starts so that shared_task will use this app.


from

.

celery import app

as

celery_app




4、blog/tasks.py





from

django

.

db

.

models

import

F


 


from

.

models import Article


from dailyblog import

celery

_

app


 


 


@

celery_app

.

task


def incr_readtimes

(

article_id

)

:


    

return

Article

.

objects

.

filter

(

id

=

article_id

).

update

(

read_times

=

F

(

"read_times"

)

+

1

)




這裡面添加了一個任務。任務可以通過delay方法執行,也可以周期性地執行。




這裡還需要注意,如果把上面任務的返回值賦值給一個變數,那麼程序也會被阻塞,需要等待非同步任務返回的結果。因此,實際應用不需要賦值。




上面的代碼寫好後,要執行資料庫更新:





python

manage

.

py makemigrations


python

manage

.

py

migrate

.




Django會創建了幾個資料庫,分別為:




Crontabs Intervals Periodic tasks Tasks Workers




在views.py添加非同步任務:





from

.

tasks import incr_readtimes


class

ArticleDetailView

(

BaseMixin

,

DetailView

)

:


 


 


    

def get

(

self

,

request

,

*

args

,

**

kwargs

)

:


        

.......


        

incr_readtimes

.

delay

(

self

.

object

.

id

)




這裡不需要賦值。




下面要啟動celery,我採用supervisor進程管理器來管理celery:





[

program

:

celery

]


command

=

celery

-

A

dailyblog

worker

--

loglevel

=

INFO


directory

=/

srv

/

dailyblog

/

www

/


numprocess

=

1


startsecs

=

0


stopwaitsecs

=

0


autostart

=

true


autorestart

=

true


stdout_logfile

=/

tmp

/

celery

.

log


stderr_logfile

=/

tmp

/

celery

.

err




重新載入supervisor.conf文件,然後啟動celery:





supervisorctl start celery




至此,通過celery非同步執行任務的程序寫完了。除此之外,還可以寫很多的非同步任務,發郵件就是非常典型的一種。




看完本文有收穫?請轉

發分享給更多人


關注「P

ython開發者」,提升Python技能


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python開發者 的精彩文章:

用 Python 做股市數據分析(二)
Python 爬蟲實戰:股票數據定向爬蟲
Python: 受限制的 "函數調用"
玩轉面試演算法,帶你佔領BAT!
用神經網路訓練一個文本分類器

TAG:Python開發者 |

您可能感興趣

NET Core微服務之基於Ocelot+IdentityServer實現統一驗證與授權
使用Tensorflow Object Detection API實現對象檢測
用Pytorch 實現的 Capsule Network
SpringBoot整合Mybatis實現事務控制
如何使用Cron Jobs實現Linux提權
SAP Cloud for Customer Extensibility的設計與實現
使用Jira software+Structure實現大規模跨團隊項目管理
Occipital推出MR創作工具Bridge Engine,實現密實3D映射
Python yield與實現
用 greenlet 實現 Python 中的並發
如何使用Tokenvator和Windows Tokens實現提權
Ceilometer和Monasca 能幫OpenStack實現智能運維
C#ConcurrentBag的實現原理
通過 Docker 實現在 Linux 容器中運行 Microsoft SQL Server 資料庫
基於google protobuf的gRPC實現
iStaging正式宣布VR Marker應用實現街景運用
SpaceTime Enterprises 用VR實現你的太空夢
SpringCloud如何實現Eureka集群、HA機制?
SpringCloud實現Eureka集群配置
Machine Learning(一):基於 TensorFlow 實現寵物血統智能識別