Django 6.0 自带 Tasks 到底能不能替代 Celery?跑完 3 组后台任务后我有答案了

Django 6.0 自带 Tasks 到底能不能替代 Celery?跑完 3 组后台任务后我有答案了

Django 6.0 第一次把 Tasks 框架放进了核心。看到 @task、enqueue()、队列名、优先级和任务结果这些 API,很多人的第一反应都是:以后 Django 项目是不是可以删掉 Celery 了?

我没有只看发布说明,而是在隔离环境中安装 Django 6.0.7、Celery 5.6.3,并连接本机 Redis,真实运行了三组 1.5 秒任务:

  1. 普通同步函数;
  2. Django 自带的 ImmediateBackend 和 DummyBackend;
  3. Redis + 独立 Celery Worker。

先给结论:Django Tasks 不能单独替代 Celery。它统一了"如何声明和提交任务",但不提供生产可用的消息队列与 Worker。Celery 解决的是任务如何被可靠地搬运、执行、重试和监控。

这两者不是简单的新旧替代关系,而是位于不同层次。

Django 6.0 到底内置了什么

Django 官方对 Tasks 框架的定义非常克制:它提供后台工作的"contract and plumbing",也就是任务契约和连接管道,而真正执行任务的引擎留给外部基础设施。

最小任务可以这样定义:

python 复制代码
from django.tasks import task


@task
def generate_report(report_id):
    # 生成报表
    return {"report_id": report_id, "status": "done"}

调用时不是 Celery 的 delay(),而是 Django 自己的 enqueue():

python 复制代码
result = generate_report.enqueue(42)

Tasks API 还定义了这些通用概念:

  • priority:任务优先级;
  • queue_name:目标队列;
  • backend:使用哪个任务后端;
  • run_after:最早执行时间;
  • TaskResult:任务状态、尝试次数、错误与返回值;
  • enqueue() / aenqueue():同步与异步提交接口。

这很重要。过去每个任务库都有自己的装饰器、调用方法和结果对象;Django 6.0 开始提供框架级统一接口,让业务代码有机会减少对具体队列实现的直接依赖。

但统一接口不等于任务已经在后台执行。

两个自带 Backend 都不是生产 Worker

Django 6.0 自带两个后端。

ImmediateBackend:名字叫 Task,实际仍在当前进程执行

默认配置就是 ImmediateBackend:

python 复制代码
TASKS = {
    "default": {
        "BACKEND": "django.tasks.backends.immediate.ImmediateBackend",
    }
}

它会在调用 enqueue() 时立刻执行任务。如果任务耗时 1.5 秒,请求仍然要等待 1.5 秒。

它适合:

  • 本地开发;
  • 单元测试;
  • 在真正的队列基础设施上线前,先改造业务调用接口。

它不具备把耗时工作移出 Web 请求进程的能力。

DummyBackend:返回得很快,因为它根本不执行

DummyBackend 会记录入队任务,方便测试检查,但不会执行任务函数:

python 复制代码
TASKS = {
    "default": {
        "BACKEND": "django.tasks.backends.dummy.DummyBackend",
    }
}

所以看到它在 1 ms 内返回,不能解释为"Django 后台任务性能惊人"。它只是把任务保存为测试记录,状态停留在 READY。

官方文档也明确说明:Django 内置的只有开发和测试后端,生产可用后端需要额外配置。

实战步骤与验证结果

测试环境如下:

项目 配置
Python 3.12
Django 6.0.7
Celery 5.6.3
Broker Redis,本地独立数据库编号
Worker 单独进程,--pool=solo
任务内容 sleep(1.5) 模拟邮件、报表或文件处理
轮数 5 轮

测试任务故意返回执行进程 PID,用来判断它到底在 Web/请求进程里运行,还是被独立 Worker 接走。

第一组:普通同步函数

python 复制代码
def slow_job(delay_seconds):
    time.sleep(delay_seconds)
    return {"worker_pid": os.getpid()}

直接调用时,请求进程必须等待任务结束。

第二组:Django ImmediateBackend 与 DummyBackend

python 复制代码
from django.tasks import task


@task
def django_slow_job(delay_seconds):
    return slow_job(delay_seconds)


immediate_result = django_slow_job.enqueue(1.5)
dummy_result = django_slow_job.using(backend="dummy").enqueue(1.5)

ImmediateBackend 会真正执行;DummyBackend 只记录任务。

第三组:Redis + 独立 Celery Worker

Celery 任务如下:

python 复制代码
from celery import Celery

app = Celery(
    "django_tasks_demo",
    broker="redis://127.0.0.1:6379/13",
    backend="redis://127.0.0.1:6379/14",
)


@app.task
def celery_slow_job(delay_seconds):
    time.sleep(delay_seconds)
    return {"worker_pid": os.getpid()}

启动独立 Worker:

powershell 复制代码
python -m celery -A celery_app:app worker `
  --pool=solo `
  --queues=ruyi_django_tasks_demo

提交任务并记录入队返回时间:

python 复制代码
started = time.perf_counter()
result = celery_slow_job.delay(1.5)
enqueue_ms = (time.perf_counter() - started) * 1000

实验里调用 result.get() 只是为了确认 Worker 最终执行完成并记录总耗时。真实 Web 请求里通常不应在提交任务后立刻 get(),否则又会把异步流程等成同步流程。

五轮真实结果

方案 平均返回时间 最小值 最大值 是否执行 执行进程
同步函数 1500.29 ms 1500.18 ms 1500.54 ms 是 请求进程 PID 42268
Django ImmediateBackend 1500.66 ms 1500.39 ms 1501.24 ms 是 请求进程 PID 42268
Django DummyBackend 0.31 ms 0.16 ms 0.84 ms 否 无
Celery 入队返回 13.66 ms 0.68 ms 65.18 ms 是 Worker PID 37412

Celery 任务的平均完整完成时间是 1515.71 ms。任务本身并没有被"加速":它仍然需要约 1.5 秒。真正改变的是 Web 请求只负责把消息送进队列,耗时工作由另一个进程完成。

这也是后台任务最关键的价值:不是让工作凭空变快,而是让请求线程不用陪它一起等。

首轮 Celery 入队时间较高,主要包含首次建立 Broker 连接的成本;后续轮次最低降到 0.68 ms。因此不能拿一次冷启动结果代表长期吞吐,也不能把这组本地数据直接当成生产性能承诺。

Django Tasks 和 Celery 的能力边界

能力 Django 6.0 Tasks 核心 Celery
统一任务声明与入队接口 是 有自己的 API
自带生产 Worker 否 是
自带生产消息传输 否 支持 Redis、RabbitMQ 等 Broker
重试、路由、并发控制 取决于外部 Backend 成熟支持
定时与复杂工作流 取决于外部 Backend Celery Beat、Canvas 等生态
测试时立即执行或只记录 内置支持 可用 eager 等配置
结果监控与运维工具 取决于 Backend 有成熟生态

所以"Django Tasks 能不能替代 Celery"需要拆成两个问题:

  1. 能不能替代 Celery 的业务调用接口? 有可能。使用兼容的生产 Backend 后,业务可以围绕 Django 的 @task 与 enqueue() 编写。
  2. 能不能替代 Celery 的队列、Worker 和运维能力? Django 核心本身不能。

新项目到底应该怎么选

选择 Django Tasks + 生产 Backend

适合这些情况:

  • 新建 Django 6.0 项目,希望先统一任务接口;
  • 任务模型简单,以发邮件、生成缩略图、轻量数据处理为主;
  • 已经验证某个外部 Backend 支持所需的延迟、优先级、结果查询和异步任务能力;
  • 希望未来更换任务实现时,尽量少改业务层。

不要只看 Backend 能否安装。Django Tasks 为后端定义了 supports_defer、supports_priority、supports_get_result、supports_async_task 等能力标志,选型时应逐项核对。

继续使用 Celery

适合这些情况:

  • 现有系统已经稳定使用 Celery;
  • 需要任务重试、限流、路由、多队列、定时任务或复杂工作流;
  • 需要多台机器或多类 Worker;
  • 已有 Redis/RabbitMQ、监控和部署体系;
  • 团队已经积累 Celery 故障处理经验。

仅仅因为 Django 6.0 新增 Tasks,就把成熟 Celery 系统整体重写,通常没有收益。

三个最容易踩的坑

坑一:把 enqueue 当成一定异步

enqueue() 的真实行为由 Backend 决定。默认 ImmediateBackend 仍会阻塞当前调用者。

坑二:测试很快,就以为生产可用

DummyBackend 不执行任务;ImmediateBackend 不离开当前进程。两者都不能证明生产队列正常。

坑三:数据库事务还没提交,Worker 已经开跑

创建订单后立刻提交邮件任务时,Worker 可能早于数据库事务提交读取订单。通用做法是提交成功后再入队:

python 复制代码
from django.db import transaction

transaction.on_commit(lambda: generate_report.enqueue(report_id))

Celery 的 Django 集成也提供 delay_on_commit() 来处理这一常见场景。任务参数最好传主键等稳定标识,让 Worker 执行时重新读取最新数据,而不是直接序列化整个模型对象。

Windows 实验需要特别说明

本文为了在本机完成可重复验证,Celery Worker 使用了 --pool=solo。Celery 官方目前不承诺 Windows 支持,这个配置适合演示独立进程与消息队列链路,不代表生产部署建议。

生产环境通常应在 Linux 上根据任务类型评估 Worker 并发模型,并使用正式维护的 Redis 或 RabbitMQ 服务。

结论:Django Tasks 不能单独替代 Celery

Django 6.0 Tasks 最重要的意义,不是"Django 把 Celery 做进核心了",而是 Django 终于提供了一套框架级任务语言:

  • 用 @task 声明任务;
  • 用 enqueue() 提交任务;
  • 用 Backend 隔离具体执行设施;
  • 用统一的结果和能力模型描述任务状态。

但协议不会自己执行任务。没有生产 Backend、Broker 和 Worker,耗时工作仍然不会离开请求进程。

因此我的答案是:Django Tasks 可以降低业务代码对具体任务库的耦合,但它不能单独替代 Celery。对于已有复杂异步体系的项目继续用 Celery;对于 Django 6.0 新项目,可以优先采用 Tasks API,再认真选择生产 Backend。

参考资料

相关推荐
FITA阿泽要努力2 分钟前
/goal 命令:给 Agent 设定目标
服务器·人工智能·python·agent
鸠摩智首席音效师6 分钟前
如何清理 ASP.NET 临时文件 ?
后端·asp.net
铁皮饭盒7 分钟前
刷到 FDE 岗位那一刻,我还以为前端又活了
前端·后端
小小张说故事24 分钟前
Python 的 dict 为什么插入顺序不会乱?拆开 3.6 的紧凑布局:indices 与 entries 两张表
python
椰萝Yerosius25 分钟前
严正声明 | 博主已正式放弃CSDN作为博客平台
python
利威尔xu34 分钟前
Go GMP 调度器 10 个高频追问:3 个线上故障让 P99 从 80ms 飙到 2s、10 万 goroutine 泄漏
开发语言·后端·面试·性能优化·golang
肖永威41 分钟前
python版微电网仿真工具的前端托管选型:从http.server到FastAPI StaticFiles
前端·python·http·fastapi
梦影_43 分钟前
MySQL进阶教程(二)—— 储存过程与触发器(下)
开发语言·数据库·后端·sql·mysql·oracle·数据库开发
IT_陈寒43 分钟前
为什么你应该学习Java?
前端·人工智能·后端
AINative软件工程1 小时前
LLM 应用的 Read-Your-Writes 一致性工程实践:写完就读,模型却返回旧数据
后端