终於要进入 Celery 这个主题了,还记得我在 Day 24 说过介绍 Flask-Mail 的另一部分原因後面再说吗,结果好像就没有下文了,是因为 Celery 这个东西在介绍它之前要先讲一下 Redis ,然後就不小心讲了两篇了。
好了,回归正题 Celery 到底是什麽(绝对不是你认识的那个芹菜)?为什麽介绍 Flask-Mail 的一部分原因跟 Celery 有关?又为什麽要先讲完 Redis 才能开始介绍它呢?
首先 Celery 是一个由 Python 开发的分散式任务处理系统,能够将一些需要较长时间处里的任务交由其他机器运行,提高回应速度。
讲完了 Celery 是什麽之後,介绍 Flask-Mail 另一部分的原因想必你也在实做过它之後也就能够理解了吧(有吧,你应该有发现寄信超慢的吧)。
而先介绍 Redis 的原因当然是 Celery 会使用到 Redis 的功能啦。
再详细介绍之前先来看一张 Celery 的架构图。
从这张图我们可以看出来,Broker 就是放置待执行任务的地方, Backend 是放置任务完成後的结果的地方,而 Worker 就是执行任务的地方。看到这里你可能在想 Redis 呢?它在干嘛?为啥又需要它了?Redis 在 Celery 中主要是当作 Broker 跟 Backend 用的(废话,不然它还能当 Worker?)。
开始使用之前,我们先来理解一下问题,最主要的问题就是 Flask-Mail 寄信太慢、太花时间,导致回应变慢。所以需要将处里的流程改成这样(图有点丑丑的不要介意):
所以要将寄信的部分包装成一个任务交由其他机器处理,让本机不会卡在寄信而回应变慢。当其他机器处理好之後再传出一个消息回应就可以了(也可以不传啦)。
好啦,大概理解了流程,就要来实做了,既然要使用到 Redis ,那还是回到我们的虚拟机吧。再开一个新的专案,并且把架构弄好,像这样:
ithomo_celery
├── base
│ └── __init__.py # 初始化
├── templates
│ └── mail.html # 寄信
├── tasks
│ ├── __init__.py # 初始化
│ └── mail.py # 寄信任务
├── app.py # 主要的档案
├── config.py # 设定档
├── Pipfile # 不管它,建立虚拟环境时自己会出现
└── Pipfile.lock # 不管它,安装套件时自己会出现
先来看一下比较不重要的 mail.html
吧。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Send Mail</title>
</head>
<body>
<div>
<h1>{{ status }}</h1>
</div>
<h1>Hello</h1>
<h2>Send Mail</h2>
<form action="/mail" method="POST">
<fieldset>
<legend>Send mail</legend>
<label>收件人</label><br />
<input type="email" name="recipient" required /><br />
<label>标题</label><br />
<input type="text" name="title" /><br />
<label>内容</label><br />
<input type="text" name="content" /><br />
<input type="submit" value="送出" />
</fieldset>
</form>
</body>
</html>
再来看一下突然出现、不太能从名字猜到是什麽的 base/__init__py
from flask import Flask
from flask_mail import Mail
import config
# templates 的位置记的修改一下
app = Flask(__name__, template_folder='../templates')
# 设定档里面不要忘记要设定有关 Email 的各种设定
app.config.from_object(config.DevelopmentConfig)
mail_app = Mail(app)
接着看 tasks 里面是甚麽
tasks/__init__.py
from celery import Celery
import time
# 这边我把 Backend 跟 Broker 分开主要是为了让我可以用 redis-cli 看 内容
# Backend 跟 Broker 也可以为同一个资料库
celery_app = Celery(
__name__,
backend = 'redis://localhost:6379/0',
broker = 'redis://localhost:6379/1',
)
# 如果跟 Celery 实体不在同一个位置的话就必须进行 import
celery_app.conf['imports'] = ('tasks.mail', )
# 如果跟 Celery 实体在同一个位置的话则不必
@celery_app.task
def add(a, b):
time.sleep(5)
return a + b
tasks/mail.py
from flask_mail import Message
from base import app, mail_app
from tasks import celery_app
@celery_app.task
def send_mail(recipients, title, content):
with app.app_context():
msg = Message(title, recipients=[recipients])
msg.body = content
mail_app.send(msg)
最後再来看一下 app.py
from base import app
from flask import make_response, redirect, render_template, request, url_for
from tasks.mail import send_mail
@app.route('/mail', methods=['GET', 'POST'])
def mail():
if request.method == 'GET':
response = make_response(render_template('mail.html'))
elif request.method == 'POST':
recipient = request.values.get('recipient')
title = request.values.get('title', '')
content = request.values.get('content', '')
''' 直接寄信 '''
# msg = Message(title, recipients=[recipient])
# msg.body = content
# mail_app.send(msg)
''' 使用任务寄信 '''
# delay 意思是发送一个任务出去,然後就不管结果了。
send_mail.delay(recipients=recipient, title=title, content=content)
# 如果想要等待结果可以使用 wait ,像这样
# send = send_mail.delay(recipients=recipient, title=title, content=content)
# send.wait()
response = make_response(render_template('mail.html', status='Send success'))
else:
response = make_response(redirect(url_for('index')))
return response
if __name__ == '__main__':
app.run()
这样大概就可以了。接下来就可以分别启动 redis-server 、 Flask 以及你还不知道怎麽使用的 Worker(因为没有别台机器可以分担了,所以只好委屈一下你手上这台。还有记的是分 3 个 terminal 个别开喔)。
# 启动 redis-server
$ src/redis-server
# 启动 Flask
$ pipenv run python app.py
# 启动 Worker | -A 後面的参数是指向 Celery 的实例
$ pipenv run celery -A tasks.celery_app worker
然後就可以打开 http://localhost:5000/mail
测试一下了,你会发现回应的速度快了很多。如果要有个明确的数字证明真的有变快,不是心理作用,可以进行以下的操作。
$ pipenv install flask-debugtoolbar
base/__init__.py
from flask import Flask
from flask_mail import Mail
from flask_debugtoolbar import DebugToolbarExtension
import config
# templates 的位置记的修改一下
app = Flask(__name__, template_folder='../templates')
# 设定档里面不要忘记要设定有关 Email 的各种设定
app.config.from_object(config.DevelopmentConfig)
mail_app = Mail(app)
toolbar = DebugToolbarExtension(app)
然後再打开 http://localhost:5000/mail
的时候点一下左边的黑色框框,再点一下左下角的红色勾勾,就可以显示回应请求所费的时间了(如果想知道这是什麽,可以去看一下 flask-debugtoolbar ,简单的一个开发时 Debug 小工具而已)。
如果使用了 Celery 寄信时,回应请求所费时间大概在 300 毫秒左右。
如果不使用 Celery 寄信时,回应请求所费时间大概在 1800 毫秒左右。
由此可知的确减少了回应等待时间,就能够提高使用者体验了。
那麽就大概这样,Celery 算是简单的东西,不过设定的东西略为复杂,所以要细心地进行设定。
大家掰~掰~
<<: Day27 用python写UI-聊聊Treeview(一)
>>: Day27-TypeScript(TS)的命名空间(Namespace)与模组(Modules)
自己常常在写程序的时候,因为习惯一种写法就很自然写下去,不太会去思考为什麽要这样用,就像每天早上都会...
Portals 是一种让 children 可以 render 到 parent component...
现在死亡後有了两个选项,一个重新开始游戏,一个是回到标题,目前只有一个场景,所以第一步快速制作一个开...
一般写程序的时候,我会将HTML和Javascript分开来写,但react提供了JSX的语法,将h...
github: https://github.com/wilsonsujames/webcam/tr...