django開發傻瓜教程-3-celery異步處理

Ref:html

https://www.jianshu.com/p/6f8576a37a3e前端

https://blog.csdn.net/Demo_3/article/details/78119951python

https://blog.csdn.net/spur_man/article/details/79550917ajax

https://my.oschina.net/37Y37/blog/1920149redis

http://docs.jinkan.org/docs/celery/getting-started/next-steps.html數據庫

https://www.ctolib.com/topics-130539.html#django


 

爲何選擇Celery

當前的需求是:我用form從前端拿到了提交的數據,因爲須要處理一點時間(也許不少用戶同時提請求呢)雖然感受暫時想多了=.=json

若是處理時間過長,那麼一方面頁面可能會超時,另外一方面,用戶等待過久也是不合適的。因此如今但願,在用戶提交數據後,馬上就服務器

能收到一個回覆(好比說task ID),等到任務結束後,通知用戶,用這個ID就能夠獲取結果(固然能夠是服務器靠這個ID來輸出結果)。架構

我也考慮過用ajax直接部分刷新頁面,可是感受對於長時間的併發任務,可能不是很合適(看到的ajax例子都是很簡單的,不是很懂是否是不適合複雜的計算邏輯?)。總之,爲了之後的發展,仍是學一下水芹菜吧。

概念

Celery 的基本架構採用典型的生產者—消費者模式,主要由三部分組成:broker(消息隊列)、workers(消費者:處理任務)、backend(存儲結果)。Celery本身不提供消息服務,可是能夠和提供消息服務的中間件集成。這裏推薦的broker有RabbitMQ(官網推薦)和Redis。Workers能夠併發地運行在分佈式的節點上。
實際應用時,用戶從 Web 前端發起一個請求,而後將請求所要處理的任務丟入 broker中,由空閒的 worker 去處理,處理的結果會暫存在後臺數據庫 backend 中。
處理場景

異步任務處理:例如給註冊用戶發送短消息或者確認郵件任務。

大型任務:執行時間較長的任務,例如視頻和圖片處理,添加水印和轉碼等,須要執行任務時間長。

定時執行的任務:支持任務的定時執行和設定時間執行。例如性能壓測定時執行。

安裝

pip install celery

爲了讓celery中執行任務的結果返回Django,再裝一個

sudo pip install django-celery-results

使用redis作broker和backend,安裝:

sudo apt-get install redis
sudo
pip install redis

 若是apt-get有錯誤,請用下面的命令

sudo apt-get install redis --fix-missing

開啓redis服務

redis-server

報錯

我就知道不會一路順風的:)

解決:1. 找到redis-server進程,kill

2. 接着發現redis-server進程仍然存在,殺不掉:)

因此使用中止服務的命令。必要的話要用sudo。

/etc/init.d/redis-server stop

而後再重啓redis-service便可

 如今正式來寫Celery了。首先看一下目錄結構:

配置階段先改celery.py和__init__.py

# Celery.py
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery, platforms

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'probe.settings')

app = Celery('probe')

# Using a string here means the worker don't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()

# Allow root user run celery
platforms.C_FORCE_ROOT = True

@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))

__init__.py

from __future__ import absolute_import, unicode_literals

# 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

__all__ = ['celery_app']

而後進入根目錄

celery worker -A probe -l info

你覺得這樣就能夠了?報錯:

這是由於咱們的水芹找不到redis啊:)因此要修改上面的celery.py

# redis是broker和backend
app = Celery('probe', backend='redis', broker='redis://localhost')

如今來配置一下celery。上面的修改暫時取消,咱們統一在settings.py裏配置celery。

CELERY_BROKER_URL = 'redis://localhost:6379'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_BACKEND = 'redis'
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERYD_MAX_TASKS_PER_CHILD = '1'

  # celery在長時間運行後可能出現內存泄漏,須要添加這個配置,表示每一個worker執行了多少個任務就死掉

# INSTALLED_APPS裏再添加一個'django_celery_results'

而後migrate一下變化

python manage.py migrate django_celery_results

如今來真正寫任務了:task.py

這個task.py在每一個app下都要有,並且名稱不能改變。

from __future__ import absolute_import, unicode_literals
from celery import shared_task

@shared_task
def longtime_test():
# 在這裏寫操做

而後在views.py裏(我這裏是把design2.py和主頁design-post綁在一塊兒的,因此我寫到design2.py裏去)

longtime_test.delay()

補一刀:

在design2.py裏,我這麼寫(省略其餘)這裏只是簡單測試一下:

import task

def design_post(request):
    ...
    if request.POST:
        result = task.longtime_test.delay(ctx['target_definition'], ctx['target_species'])
        while True:
            if result.ready():
                print "celery fried!"
                break;
    ...

事實上我第一次遇到了報錯

當時寫的是from task import longtime_test

我改爲上面的寫法以後,重啓celery,就沒有報錯:celery正確輸出字符串(畢竟我只作了字符串鏈接啊攤手)

並且django後臺這裏也正確反饋了(黃色標識)紅色的是以前報錯狀態的顯示。由於longtime_test函數同樣返回了,因此仍是會跳出循環。

 

 好了我如今要去寫業務代碼了,配置方面的任務暫時告一段落:)

相關文章
相關標籤/搜索