问题
- 用户发起request,并等待response返回。在views中,可能需要执行一段耗时的程序,那么用户就会等好长时间,造成不良好的用户体验
- 网站每小时需要同步一次天气信息,但是http请求是需要触发的,难道要一小时请求一次吗?
解决
- 使用
celery
:
- 将耗时操作放到
celery
中执行
- 使用
celery
定时执行
celery
- **任务task:**就是一个python函数
- **队列queue:**将要执行的任务加入到队列中
- **工人worker:**在一个新进程中,负责执行队列中的任务
- **代理broker:**负责调度,在布置环境中使用redis
问题示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> </head> <body> <form action="/register/" method="post"> {% csrf_token %} <input type="text" name="username" value=""><br> <input type="password" name="password" value=""><br> <input type="submit" value="注册"> </form> </body> </html>
|
安装
1
| pip install celery==3.1.25
|
1
| pip install celery-with-redis==3.0
|
1
| pip install django-celery==3.2.1
|
-
注册应用
1 2 3 4 5 6 7 8 9 10 11
| INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'myApp', 'tinymce', 'djcelery', ]
|
-
在settings.py
末尾添加以下代码
1 2 3 4 5 6 7 8
| import djcelery
djcelery.setup_loader()
BROKER_URL = 'redis://:密码@127.0.0.1:6379/0'
CELERY_IMPORES = ("myApp.task")
|
在应用目录下创建task.py文件,用于书写任务
1 2 3 4 5 6 7 8 9
| import time from celery import task
@task def longIO(): print("开始耗时操作……") time.sleep(10) print("结束耗时操作……")
|
在工程目录下的project目录下创建一个名为celery.py的文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| from __future__ import absolute_import
import os from celery import Celery from django.conf import settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'whthas_home.settings')
app = Celery('portal')
app.config_from_object('django.conf:settings') app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request))
|
在工程目录下的project目录下的__init__.py
文件中添加
1
| from project.celery import app as celery_app
|
迁移
-
生成celery
需要的数据表
1
| python manage.py migrate
|
将任务添加到队列
1 2 3 4 5 6 7 8 9 10 11
| from myApp.task import longIO
def register(request): if request.method == "GET": return render(request, "myApp/register.html") else: username = request.POST.get("username") passwd = request.POST.get("passwd") longIO.delay() return HttpResponse("注册成功!!")
|
启动redis
1
| redis-server.exe redis.windows.conf
|
启动worker
1
| python manage.py celery worker --loglevel=info
|
启动Django服务
1
| python manage.py runserver
|