python之celery异步处理

  在写个人博客项目的时候,涉及到邮件验证码和短信验证码的发送的功能,应该异步地去执行,而不是同步形成阻塞。这时就要用到python的扩展库celery。

  celery是一个强大的分布式任务队列的异步处理组件,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。

  Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成。

消息中间件:

  Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ, Redis等等

任务执行单元:

  Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中。

任务结果存储:

  Task result store用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, redis等

  个人理解,有些功能,比如发短信通知,是一个耗时任务,如果都扎堆在一起去执行,同步操作一次执行一个,一次发一条短信,势必会形成阻塞。例如美团外卖,中午12点整的下单人数100个,每个人下单完成后系统都要发个短信给用户说“下单成功”,每次发短信时间假如是1s,那就要100s发完这100条短信,那第101个人下单完成后要等100秒才能收到短信,这是什么用户体验?很显然,我们不能一次发一条短信,而应该并发,一次发N条。这些并发技术是比较底层的,写起来很麻烦,而celery就帮我们封装好了这些并发技术,我们要做的就是通过celery去调动执行并发。

使用场景:

  异步任务:将耗时操作任务提交给Celery去异步执行,比如发送短信/邮件、消息推送、音视频处理等等

  定时任务:定时执行某件事情,比如每天数据统计

 

之前在cms后台修改邮箱的时候点击发送验证码邮件,会有大概1.2s的延时然后弹出发送成功的对话框。这个延时就是调用flask扩展mail发送邮件的耗时,这时在同步场景下执行的。现在换成celery的异步操作:

 1 from celery import Celery
 2 from flask_mail import Message
 3 from exts import mail
 4 from flask import Flask
 5 import config
 6 app = Flask(__name__)
 7 app.config.from_object(config)
 8 mail.init_app(app) # 初始化app
 9 
10 def make_celery(app):
11     celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'],broker=app.config['CELERY_BROKER_URL'])
12     celery.conf.update(app.config)
13     TaskBase = celery.Task
14     class ContextTask(TaskBase):
15         abstract = True
16         def __call__(self, *args, **kwargs):
17             with app.app_context():
18                 return TaskBase.__call__(self, *args, **kwargs)
19     celery.Task = ContextTask
20     return celery
21 
22 celery = make_celery(app)
23 
24 @celery.task
25 def send_mail(subject,recipients,body):
26     message = Message(subject=subject,recipients=recipients,body=body)
27     mail.send(message)

 

之后点击发送验证码就是立即弹出alert了。用户体验极佳。

 

 

这里要注意,目前我这个项目运行在window10上,但是celery对windows不太友好,4.x版本后不支持windows,要用eventlet去解决。eventlet是Python的并发网络库。

在命令行开启:celery -A tasks.celery worker --pool=eventlet --loglevel=info

后来发现一定几率出现莫名的报错。

将eventlet改为solo就可以了:

celery -A tasks.celery worker --pool=solo --loglevel=info

 

 

 

 

posted @ 2020-06-15 17:59  天青色wy  阅读(958)  评论(2编辑  收藏  举报