django异步进程

从我开始用Python以来,我就一直有个疑问,Python到底如何多线程运行?从整体结构和代码特性来看,Python似乎只针对单线程应用。直到昨天我完成了邮箱配置,发现发布评论时的响应时间会比没配置邮箱的时候慢上1~2s左右。于是我就想到,发送邮件大可不必和评论发布同时进行,可以先发布评论,邮件由另一个线程发送。

根据网络上的文章,我选用了Celery+redis的方案进行Django异步任务。

异步任务的配置

因为我的服务器配置了宝塔面板,可以很快捷的从软件商店安装redis,没有宝塔面板的,可以参照redis官方文档安装Releases · tporadowski/redis (github.com)

再然后是python的redis插件及celery插件,我选用的版本如下:

 celery==5.0.5
 redis==3.5.3
 eventlet # Windows环境调试时使用,Linux服务器无需安装

在Django项目settings.py中添加如下配置:

# 异步任务
# 最重要的配置,设置消息broker,格式为:db://user:password@host:port/dbname
# 如果redis安装在本机,使用localhost
# 如果docker部署的redis,使用redis://redis:6379
CELERY_BROKER_URL = "redis://127.0.0.1:6379/0"

# celery时区设置,建议与Django settings中TIME_ZONE同样时区,防止时差

CELERY_TIMEZONE = TIME_ZONE
# 为django_celery_results存储Celery任务执行结果设置后台
# 格式为:db+scheme://user:password@host:port/dbname
# 支持数据库django-db和缓存django-cache存储任务状态及结果
# CELERY_RESULT_BACKEND = "django-db"
# celery内容等消息的格式设置,默认json
# CELERY_ACCEPT_CONTENT = ['application/json', ]
# CELERY_TASK_SERIALIZER = 'json'
# CELERY_RESULT_SERIALIZER = 'json'

# 为任务设置超时时间,单位秒。超时即中止,执行下个任务。
CELERY_TASK_TIME_LIMIT = 5

# 为存储结果设置过期日期,默认1天过期。如果beat开启,Celery每天会自动清除。
# 设为0,存储结果永不过期
# CELERY_RESULT_EXPIRES = xx

# 任务限流(10次/s)
CELERY_TASK_ANNOTATIONS = {'tasks.add': {'rate_limit': '10/s'}}

# Worker并发数量,一般默认CPU核数,可以不设置
# CELERY_WORKER_CONCURRENCY = 2

# 每个worker执行了多少任务就会死掉,默认是无限的
# CELERY_WORKER_MAX_TASKS_PER_CHILD = 200

大部分配置并未用上,但为了以后需要用时不用到处乱找,先写在这里。

在Django主目录(settings.py所在目录)添加celery.py,内容如下:

import os
from celery import Celery

# 设置环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'my_blog.settings')

# 实例化
app = Celery('my_blog')

# namespace='CELERY'作用是允许你在Django配置文件中对Celery进行配置
# 但所有Celery配置项必须以CELERY开头,防止冲突
app.config_from_object('django.conf:settings', namespace='CELERY')

# 自动从Django的已注册app中发现任务
app.autodiscover_tasks()

然后在主目录的__init__.py添加以下代码:

from .celery import app as celery_app
__all__ = ('celery_app',)

至此,Django异步任务就配置完成。

异步任务的使用

编写异步任务分为两步,1、定义异步方法;2、调用异步方法。

定义异步方法时,需要在APP中添加tasks.py,然后使用装饰器@shared_task装饰异步方法。一个典型的异步方法应该如下:

from celery import shared_task
from django.core.mail import send_mail


@shared_task
def comment_send_mail(subject, body, setting, to_email):
    send_mail(subject, body, setting, to_email)

需要注意的是,当Celery配置的数据传送为Json时,异步方法不允许传入字典,否者会报错。也就是说,不能将request请求传入异步方法中。

调用异步方法时,如果像平常一样调用,程序依然会等方法执行完毕后再进行下一步,而不是进入异步线程。异步调用应当如下书写:

comment_send_mail.delay(subject, body, xxx, [xxx@email.com,x2x@email.com])

总结

采用异步任务,让整体工作流程快了很多,同时Django异步任务配置并不困难,更多细节及定时任务等内容,可以参照以下文章:Django进阶:万字长文教你使用Celery执行异步和周期性任务(多图) - 知乎 (zhihu.com)。文章内容比CSDN上千篇一律的复制文章更加靠谱。



登录后回复

共有0条评论

目 录