听说Django与芹菜配合更美味

1,172 阅读7分钟
原文链接: mp.weixin.qq.com

作者:土豆豆,一个做网站开发的机器学习兼职安全的学生

博客主页https://www.zhihu.com/people/tu-dou-dou-27-10

注:本文使用的开发环境如下,如不同系统或环境之间可能存在差异,本文不做其它说明

  1. 操作系统 : MacOS 10.13.4

  2. Python版本 : Python 3.5.4

  3. Django版本 : 2.0.5

  4. celery 版本 : 4.1.0

  5. celery后端 : Redis

  6. 特别强调 本文使用的是原生的 celery,因为celery官方已经在3.x版本之后将 django-celery 兼容于 celery,不再使用 django-celery

0x00 前言

最近要写个Web项目,为了简便就选择使用Django作为后端开发了,突然发现程序要使用异步架构,在此原谅我废话几句说明为什么要使用异步架构,什么又是异步架构(我相信你在看这篇文章的时候已经对网络请求和回应有所了解,也应当知道Django的请求回应流程)

言归正传,因为Django的请求回应机制,必须在执行完语句后才返回请求,但是在一些特殊的环境下,这样的操作就会带来很大的不便,比如程式在收到一个请求之后,要做很费时间的操作,用户就会出现迟迟收不到网站的响应,比如我下面的例子。呃,先放个图片镇镇场。

0x01 未做异步处理时的场景

部分代码如下

为了使效果更加明显,我在函数里面添加了sleep函数,模拟请求,

其实sleep函数的存在感觉就是为我这样的“流氓开发者”而存在的,不给钱就不给优化,故意增加sleep的时间,滋滋(捂脸)。别打我

这里,我们发现当请求函数里面存在费时的函数,请求就会出现延时,降低用户体验。接下来,我要开始表演啦!!! 前方高能

0x02 听说 Django 与 celery 配合更美味

0x02-0 安装 celery

读到这里,我暂且认为您是会安装Django并且会写Django的基础语句的,如果不是,建议您点个赞之后关闭本网站,下面的内容可能会让您感到糟糕。

首先,执行安装,安装姿势详见 First Steps with Celery,如果不想打开请直接安装下面的方式安装,但如果您想更换 celery 的后端或者安装时出现了错误,建议您优先查看此网站进行解决。

Mac OS X 安装

  1. $ brew install Redis    # Redis 安装,需提前安装 brew

  2. $ pip install celery    # pip 安装celery库

  3. $ pip install redis     # pip 安装 redis库

如果您没有安装 brew,建议您先安装 brew 参考 brew安装

Ubuntu 安装

  1. $ sudo apt install redis    # Redis 安装

  2. $ pip install celery        # pip 安装celery库

  3. $ pip install redis         # pip 安装 redis库

Linux 安装

请访问 redis 下载 最新的安装包,本文使用的是在书写本文这个时间时最新的安装包,如官方发布更新,恕本文不另行通知更改。

  1. $ wget http://download.redis.io/releases/redis-4.0.9.tar.gz

  2. $ tar xzf redis-4.0.9.tar.gz

  3. $ cd redis-4.0.9

  4. $ make

  5. # make完后 redis-4.0.9 目录下会出现编译后的redis服务程序redis-server,还有用于测试的客户端程序redis-cli,两个程序位于安装目录 src 目录下:

  6. # 下面启动redis服务.

  7. $ cd src

  8. $ ./redis-server

Windows 安装 参考菜鸟教程-Redis 安装

作者未进行尝试,所有错误请自行 Google

下载地址: https://github.com/MSOpenTech/redis/releases

Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择,这里我们下载 Redis-x64-xxx.zip压缩包到 C 盘,解压后,将文件夹重新命名为 redis。

打开一个 cmd 窗口 使用cd命令切换目录到 C:\redis 运行 redis-server.exe redis.windows.conf 。

如果想方便的话,可以把 redis 的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个 redis.windows.conf 可以省略,如果省略,会启用默认的。输入之后,会显示如下界面:

0x02-1 编写代码

部分代码截图如下

代码文件(./demo/demo/settings.py)

  1. ···

  2. # Celery settings

  3. CELERY_BROKER_URL = 'redis://localhost'

  4. #: Only add pickle to this list if your broker is secured

  5. #: from unwanted access (see userguide/security.html)

  6. CELERY_ACCEPT_CONTENT = ['json']

  7. CELERY_RESULT_BACKEND = 'redis://localhost'

  8. CELERY_TASK_SERIALIZER = 'json'

代码文件(./demo/demo/celery.py)

  1. from __future__ import absolute_import, unicode_literals

  2. import os

  3. from celery import Celery

  4. # set the default Django settings module for the 'celery' program.

  5. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'demo.settings')

  6. app = Celery('demo')

  7. # this ‘demo’ is your project name !!!

  8. # Using a string here means the worker doesn't have to serialize

  9. # the configuration object to child processes.

  10. # - namespace='CELERY' means all celery-related configuration keys

  11. #   should have a `CELERY_` prefix.

  12. app.config_from_object('django.conf:settings', namespace='CELERY')

  13. # Load task modules from all registered Django app configs.

  14. app.autodiscover_tasks()

代码文件(./demo/app/tasks.py)

  1. import time

  2. from celery import Celery

  3. celery_app = Celery('tasks', backend='redis://localhost', broker='redis://localhost')

  4. # this is celery settings

  5. # this is a function about need many time

  6. @celery_app.task

  7. def add(a, b):

  8.    time.sleep(5)

  9.    return a + b

编辑完成代码之后,开始运行web程式吧

首先,我们要启动 redis 服务,在终端执行 redis-server 启动服务,如看见类似下面这样的输出,且没有报错,则redis启动成功。

  1. 5433:C 14 May 11:24:01.463 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo

  2. 5433:C 14 May 11:24:01.465 # Redis version=4.0.9, bits=64, commit=00000000, modified=0, pid=5433, just started

  3. 5433:C 14 May 11:24:01.465 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf

  4. 5433:M 14 May 11:24:01.467 * Increased maximum number of open files to 10032 (it was originally set to 256).

  5.                _._                                                  

  6.           _.-``__ ''-._                                            

  7.      _.-``    `.  `_.  ''-._           Redis 4.0.9 (00000000/0) 64 bit

  8.  .-`` .-```.  ```\/    _.,_ ''-._                                  

  9. (    '      ,       .-`  | `,    )     Running in standalone mode

  10. |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379

  11. |    `-._   `._    /     _.-'    |     PID: 5433

  12.  `-._    `-._  `-./  _.-'    _.-'                                  

  13. |`-._`-._    `-.__.-'    _.-'_.-'|                                  

  14. |    `-._`-._        _.-'_.-'    |           http://redis.io        

  15.  `-._    `-._`-.__.-'_.-'    _.-'                                  

  16. |`-._`-._    `-.__.-'    _.-'_.-'|                                  

  17. |    `-._`-._        _.-'_.-'    |                                  

  18.  `-._    `-._`-.__.-'_.-'    _.-'                                  

  19.      `-._    `-.__.-'    _.-'                                      

  20.          `-._        _.-'                                          

  21.              `-.__.-'                                              

  22. 5433:M 14 May 11:24:01.470 # Server initialized

  23. 5433:M 14 May 11:24:01.470 * DB loaded from disk: 0.000 seconds

  24. 5433:M 14 May 11:24:01.470 * Ready to accept connections

  25. ^C5433:signal-handler (1526271328) Received SIGINT scheduling shutdown...

  26. 5433:M 14 May 12:15:28.345 # User requested shutdown...

  27. 5433:M 14 May 12:15:28.345 * Saving the final RDB snapshot before exiting.

  28. 5433:M 14 May 12:15:28.348 * DB saved on disk

  29. 5433:M 14 May 12:15:28.348 # Redis is now ready to exit, bye bye...

之后新建终端,执行命令 python manage.py runserver  ,之后再新建一个终端,执行命令 celery-A demo worker-l info (注: 此处的demo为Django项目名称),没有看到报错的话,就证明运行成功了。

再次访问网址

我们来看一下日志

在访问网址5秒之后,自定义的add函数运行完成,并没有阻塞我们的访问响应。

0x03 结语

至此,我想你应该已经初步了解如何在Django中使用celery了。