为什么我需要使用异步工具来发送 Django 电子邮件

Why do I need to use asynchronous tools for sending Django email

在使用 Django 时,我注意到发送电子邮件时有延迟,为了克服这个问题,我不得不使用 Celery 工具。所以我想知道引擎盖下到底发生了什么。为什么 Django/Python 需要一个异步工具来完成这个任务。我在 Python 中了解了多线程、多处理,但如果有人能给我简要介绍一下当 Django 试图在不使用 Celery 的情况下发送电子邮件时到底发生了什么。

将发送电子邮件视为发送请求,在同步上下文中,流程如下:

  1. 发送请求
  2. 等待回复..........
  3. 收到回复

在您等待线程不能做任何其他事情的响应的整个过程中,它正在浪费 CPU 可以被其他东西使用的周期(例如服务于其他用户的请求)。

我想在这里区分一下您对异步和芹菜的使用。 Python 的实际异步实现使用 "event loop" 来发送和接收消息。 "waiting" 是在单独的 thread/process 中完成的,它专门用于接收消息,并将这些消息发送给接收者,这样发送请求的线程就不再浪费 CPU 周期等待,它将在准备就绪时由事件循环调用。这是对 python 异步工作原理的非常 模糊的描述。除非发送大量电子邮件,否则它不一定会使用户的整个过程更快。

另一方面,Celery 是一个异步任务队列,生产者(您的 Web 应用程序)在其中发送消息,代理(数据存储)存储和分发消息,消费者(工作者)从中提取消息经纪人并处理它们。消费者是一个完全独立于您的 Web 应用程序的进程(通常是一个完全独立的服务器),它使您的 Web 应用程序腾出时间来专注于 return 尽快响应客户端。通过 celery 发送电子邮件的过程如下所示:

  1. Web 应用程序向代理发送消息,return向用户发送响应。这里有一个jsonpseudo-message。 (代理实际上将消息存储为腌制对象或 JSON)
{
    "task": "my_app.send_email",
    "args": ["Subject Line", "Hello, World! This is your email contents", "to_email@example.com", "from_email@example.com"],  # 
    "kwargs": {}  # No keyword arguments
}
  1. celery worker 不断地检查代理是否有新消息要处理,如果它当前没有处理的话。有时,celery worker 会批量提取消息,因此开销较小,这是可配置的。
  2. celery worker 使用参数和关键字参数执行函数(由消息中的 "task" 定义)。

这是一个非常简单的示例,说明了为什么您可能想使用 celery 发送电子邮件,这样您就可以 return 尽快响应用户!它也非常适合较长的 运行 任务,例如处理图像缩略图:

  1. 用户上传一张图片,您将其存储在某处(例如 Amazon S3)
  2. 您向经纪人发送消息说 "execute my process_image_thumbails task with the files S3 URL as the argument"
  3. 您 return 对您的用户的响应。从用户的角度来看,它既好又快。
  4. 工作人员拿起消息,从 S3 下载文件,并将其处理成不同大小的缩略图。

当您将 celery 用于更多新用例时,您会遇到新问题。例如,如果有人在处理过程中请求缩略图,我们该怎么办?我会把它留给你的想象力。