Django中使用celery

环境,win10。项目用的数据库需提前配置好,我用的mysql。redis数据库需提前配置好,并启动,我已在服务器中配置,并将连接信息存入win10环境变量,后面的代码里从环境变量中读取连接信息。

celery的安装和配置

安装

  • pip install Django==3.2.2
  • pip install celery==4.4.0
  • pip install celery-with-redis==3.0
  • pip install django-celery-results==1.2.0 # 基于Django ORM实现了结果存储后端
  • # pip install django-celery==3.3.1 # 装不装都行,我没装,用到它的代码我写了,但注释掉了,不影响代码正常运行

配置settings.py

INSTALLED_APPS = [
    …… # Django自带的默认配置已省略
    'myApp', # Django应用名
    'celery',
    'django_celery_results' # 基于Django ORM实现了结果存储后端
]

# djcelery.setup_loader() # 需要安装django-celery 3.2.1或3.3.1,再import djcelery,在INSTALLED_APPS中添加djcelery。不写这句也行,不写的话不用安装django-celery。装的话可能在某个版本与celery扩展库或celery-with-redis扩展库冲突
BROKER_URL='redis://:'+os.getenv('CACHE_REDIS_PASSWORD')+'@'+os.environ.get('CACHE_REDIS_HOST')+':6379/1' # 任务队列,配置redis,/1是使用第1个数据库,总共是0-15。注意//后还有一个冒号
CELERY_RESULT_BACKEND='django-db' # 返回结果的存储地址,django-db是使用Django ORM对结果进行后端存储,若Django配置了mysql,则将任务信息和执行结果存入mysql中django_celery_results_taskresult表
CELERY_TASK_SERIALIZER='json' # 任务序列化和反序列化数据格式
CELERY_RESULT_SERIALIZER='json' # 结果序列化数据格式
# CELERY_ACCEPT_CONTENT=['json'] # 分布式接收数据的格式
# CELERY_TIMEZONE='Asia/Shanghai' # celery时区,已在celery.py中配置,这里不用再配置
# CELERY_ENABLE_UTC=True # 默认使用UTC时间
CELERY_TASK_RESULT_EXPIRES=60*60*24 # 后端存储的任务超过一天时,自动删除数据库中的任务数据,单位秒
CELERYD_MAX_TASKS_PER_CHILD=1000 # 每个worker执行1000次任务后,自动重启worker,防止任务占用太多内存导致内存泄漏

数据库迁移

python manage.py migrate,迁移后数据库中多出一张表,django_celery_results_taskresult,里面是每个celery任务的信息和执行结果

配置celery

在settings.py的同级目录内新建celery.py

from __future__ import absolute_import # 从绝对路径导入,只能写在第一行

import os
from celery import Celery
from django.conf import settings

os.environ.setdefault('DJANGO_SETTINGS_MODULE', '14-celery.settings') # 从当前Django工程的配置中读取配置并设置,.settings前是当前Django工程名

app = Celery('portal') # 创建celery对象,第一个参数是应用名,必须传
app.conf.timezone='Asia/Shanghai' # 配置celery时区,默认是UTC

app.config_from_object('django.conf:settings') # 指定celery的配置来源,从当前项目的配置文件获取,即上面设置的
# app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
app.autodiscover_tasks() # 让celery工人(worker)自动从已注册的所有Django应用中发现任务(task),需在应用目录内新建tasks.py,不能用其他文件名


@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))

在settings.py的同级目录中的__init__.py添加

from __future__ import absolute_import # 从绝对路径导入,只能写在第一行

import pymysql # 若用的不是mysql,不用写这两行
pymysql.install_as_MySQLdb()

from .celery import app as celery_app # 从当前目录内的celery.py中导入app,并起别名celery_app,防止与其他app重名

celery的使用

创建任务(task)

在需要使用异步任务的Django应用目录内新建tasks.py,不能用其他文件名

import time
from celery import shared_task


@shared_task # 装饰后被装饰函数成为celery任务
def waitIO():
    print('开始耗时操作') # 如网络状态差时,发邮件很慢
    time.sleep(10)
    print('结束耗时操作')

生成数据库中的表

python manage.py migrate django_celery_results,前面迁移时已生成,这步可跳过

启动celery

celery启动方式

  1. 在pycharm中新开一个终端启动,因为启动celery后还要启动项目,所以新开一个终端。
  2. 用系统自带终端启动,若用了虚拟环境,需先进入虚拟环境,并进入工程目录,再启动。

celery启动代码

注意:启动celery和项目后,若又修改了代码,则需重启celery和项目,修改才生效。

非windows平台:celery -A 工程名 worker -l info

windows平台:celery4开始不能直接在windows上运行,直接运行上面的代码并触发任务后会报错ValueError: not enough values to unpack (expected 3, got 0),网上的说法是需要装gevent或eventlet,我都试了。当然也可以装4之前的版本,但由于我的Django版本高,用celery 3.1.25时,启动项目会报错,因为扩展的源码里用的render_to_response(),新版Django中用render()取代了它,所以要改源码,同时因render()的第一个参数是request,所以也要传一个request,我就不改源码了,换用4.4.0。

用gevent

  • pip install gevent
  • celery -A 工程名 worker -l info -P gevent

启动项目,通过访问路由,正常执行task,celery控制台正常输出打印

用eventlet(测试结果说明不装也可以)

  • pip install eventlet
  • celery -A 工程名 worker -l info -P eventlet

启动项目,通过访问路由,执行task后报错,即在输出打印后报错django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 2156058693704 and this is thread id 2153981599064.

解决方法(以下两种都无需安装eventlet或gevent),[]内是可选的

  • celery -A 工程名 worker -l info [--loglevel=info] --pool=solo 或
  • celery -A 工程名 worker -l info -P solo [-c 10] # -c是协程的数量,生产环境可以用1000

用--pool=solo启动后的截图

启动项目

路由

from django.urls import path
from myApp import views

urlpatterns=[
    path('register/',views.register)
]

视图函数

from django.shortcuts import render
from myApp.tasks import waitIO
from django.http import HttpResponse

# Create your views here.


def register(request):
    if request.method=='GET':
        return render(request,'myApp/register.html')
    else:
        username=request.POST.get('username')
        password=request.POST.get('password')
        waitIO.delay() # 将celery任务(task)放入队列(queue),让工人(worker)执行,若任务有参数,在delay()内传,这里传的话即给waitIO()传参。delay()本质上是调用apply_async()
        return HttpResponse('注册成功')

模版文件register.html

<!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" /><br />
        密码:<input type="password" name="password" /><br />
        <input type="submit" value="注册" />
    </form>
</body>
</html>

celery任务执行结果

python manage.py runserver后,访问路由并提交表单,celery的控制台输出打印,且中间间隔了time.sleep()的10秒,数据库中django_celery_results_taskresult表中也存了本次任务的信息和执行结果。

获取celery任务执行结果

由于celery任务是异步执行,所以不知道它什么时候执行完,主程序也就不能立刻获得celery任务执行结果。但一些装饰器可以解决这个问题,官方文档,被装饰的函数(依然写在tasks.py中)是回调函数,这个回调函数与celery任务绑定,根据需要,根据信号量在不同的时机执行回调函数。

  • before_task_publish # 在发布任务之前执行回调函数
  • after_task_publish # 发布任务之后
  • task_prerun # 运行任务之前
  • task_postrun # 运行任务之后
  • task_success # 任务执行成功之后
  • task_failure # 任务执行失败之后
  • task_revoked # 任务取消或终止之后

以task_success为例,代码和详细介绍在下一篇文章末尾的celery发送邮件。

 

本文用到的参考链接

Django项目使用Celery - 知乎 (zhihu.com)

celery踩坑记(==4.3.0) - 知乎 (zhihu.com)

Django中使用Celery执行异步和定时任务的注意事项_大江狗-CSDN博客

在windows上 使用celery 报错_落叶无痕的博客-CSDN博客

Python Celery库不支持windows,报错 No module named ‘xxx’_HDmonster_root的博客-CSDN博客

关于Celery4.x以上在Win10下报错解决办法_请针对我谢谢的博客-CSDN博客

celery错误:DatabaseWrapper objects created in a thread can only - SegmentFault 思否

window下celery正常启动后能收到任务但不执行任务的解决办法 - 乔小生1221 - 博客园 (cnblogs.com)

celery——使用 - Ayca - 博客园 (cnblogs.com)

Python 之 Celery + Redis + Django 教程详细_YUAYU博客-CSDN博客

前言 - Celery 中文手册 (celerycn.io)

GitHub - open-source-translation/celery-cn: 🚀Celery中文手册

本文未用到的参考链接

实战教程!Django Celery 异步与定时任务 - 知乎 (zhihu.com)

Django中使用Celery的方法步骤_python_脚本之家 (jb51.net)

Django+Celery学习笔记5——定时推送消息 - 全栈测试开发日记 - 博客园 (cnblogs.com)

Django+Celery学习笔记4——django+celery+redis周期任务Crontabs设置 - 全栈测试开发日记 - 博客园 (cnblogs.com)

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值