python - Waitress 如何处理并发任务?
问题描述
我正在尝试使用 Django 和 Waitress 构建一个 python 网络服务器,但我想知道 Waitress 如何处理并发请求,以及何时可能发生阻塞。
虽然Waitress 文档提到可以使用多个工作线程,但它并没有提供很多关于它们如何实现以及 python GIL 如何影响它们的信息(强调我自己的):
当通道确定客户端至少发送了一个完整的有效 HTTP 请求时,它会使用“线程调度程序”调度一个“任务”。线程调度程序维护一个固定的工作线程池,可用于执行客户端工作(默认情况下,4 个线程)。如果在调度任务时工作线程可用,则工作线程运行该任务。该任务可以访问通道,并且可以写回通道的输出缓冲区。当所有工作线程都在使用时,计划任务将在队列中等待工作线程可用。
Stackoverflow 上似乎也没有太多信息。从问题“Gunicorn 的 gthread 异步工作者是否类似于 Waitress?” :
Waitress 有一个主异步线程来缓冲请求,并在请求 I/O 完成时将每个请求排入其同步工作线程之一。
这些陈述没有解决 GIL(至少从我的理解来看),如果有人能详细说明工作线程如何为 Waitress 工作,那就太好了。谢谢!
解决方案
以下是事件驱动异步服务器的一般工作方式:
- 启动一个进程并监听传入的请求。利用操作系统的事件通知 API 可以很容易地从单线程/进程为数千个客户端提供服务。
- 由于只有一个进程管理所有连接,因此您不希望在此进程中执行任何缓慢(或阻塞)的任务。因为那样它将阻止每个客户端的程序。
- 为了执行阻塞任务,服务器将任务委托给“工人”。工作者可以是线程(在同一进程中运行)或单独的进程(或子进程)。现在主进程可以继续为客户端提供服务,同时工作人员执行阻塞任务。
Waitress 如何处理并发任务?
和我上面描述的差不多。对于工人来说,它创建线程,而不是进程。
python GIL 如何影响它们
女服务员为工人使用线程。所以,是的,它们受到 GIL 的影响,因为它们看起来并不是真正的并发。“异步”是正确的术语。
Python 中的线程在单个进程内、单个 CPU 内核上运行,并且不并行运行。一个线程在很短的时间内获取 GIL 并执行其代码,然后 GIL 被另一个线程获取。
但是由于 GIL 是在网络 I/O 上发布的,所以只要有网络事件(例如传入的请求),父进程总是会获取 GIL,这样您就可以放心 GIL 不会影响网络绑定操作(比如接收请求或发送响应)。
另一方面,Python 进程实际上是并发的:它们可以在多个内核上并行运行。但是女服务员不使用进程。
你应该担心吗?
如果你只是在做一些小的阻塞任务,比如数据库读/写,并且每秒只为几百个用户提供服务,那么使用线程并不是那么糟糕。
为了服务大量用户或执行长时间运行的阻塞任务,您可以考虑使用外部任务队列,如Celery。这将比自己生成和管理进程要好得多。
推荐阅读
- r - RColorbrewer scale_fill_brewer 在图例键周围加上括号
- hadoop - Hive 分区方案及其对性能的影响
- r - 用“|”分割我的数据框中的字符向量 不工作
- javascript - Trying to understand how `${c}` in this string interpolation points to the elements in an array
- flutter - Flutter web get screen size
- kerberos - Keycloak:是否需要 MIT Kerberos 客户端?
- angular - Angular 构建中何时生成 index.html?
- python - 打开目录并读取不同的文件并将它们保存到不同的变量中,Python
- python - 编写和运行 DAG 任务的最简洁方法是什么?
- javascript - 选择值在jQuery中返回null