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的常見場景:
Web應用。當用戶觸發一個動作需要較長時間來執行完成時,可以把它作為任務交給celery非同步執行,執行完再返回給用戶。這點和你在前端使用ajax實現非同步載入有異曲同工之妙。
定時任務。假設有多台伺服器,多個任務,定時任務的管理是很困難的,你要在不同電腦上寫不同的crontab,而且還不好管理。Celery可以幫助我們快速在不同的機器設定不同任務。
其他可以非同步執行的任務。比如發送簡訊,郵件,推送消息,清理/設置緩存等。這點還是比較有用的。
綜上所述,第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: 受限制的 "函數調用"
※玩轉面試演算法,帶你佔領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 實現寵物血統智能識別