7

我正在尝试编写一个可扩展的自定义 Web 服务器。这是我到目前为止所拥有的:

主循环和请求解释器在 Cython 中。主循环接受连接并将套接字分配给池中的一个进程(必须是进程,由于 GIL,线程不会从多核硬件中获得任何好处)。

每个进程都有一个线程池。该进程将套接字分配给一个线程。线程调用recv(阻塞)套接字并等待数据。当一些出现时,它通过管道进入请求解释器,然后通过 WSGI 发送到在该线程中运行的应用程序。

现在我听说了 epoll 并且有点困惑。使用 epoll 获取套接字数据然后将其直接传递给进程有什么好处吗?还是我应该走通常的路线让每个线程等待recv

PS:epoll实际上是用来做什么的?似乎多线程和阻塞fd调用会完成同样的事情。

4

2 回答 2

9

如果您已经在使用多个线程,epoll则不会为您提供太多额外的好处。

关键epoll是单个线程可以同时侦听多个文件选择器上的活动(并在每个事件发生时对其进行响应),从而提供事件驱动的多任务处理,而无需产生额外的线程。线程相对便宜(与生成进程相比),但每个线程需要一些开销(毕竟,它们每个都必须维护一个调用堆栈)。

如果您愿意,您可以使用 将您的池进程重写为单线程epoll,这将减少您的整体线程使用计数,但当然您必须考虑这是否是您关心的事情 - 通常,对于低每个工作人员同时请求的数量,产生线程的开销无关紧要,但是如果您希望每个工作人员能够处理 1000 个打开的连接,那么开销可能会变得很大(这就是epoll亮点)。

但...

您所描述的内容听起来很可疑,就像您基本上是在重新发明轮子一样-您的:

  1. 主循环和请求解释器
  2. 进程池

听起来几乎完全一样:

  1. nginx(或任何其他负载均衡器/反向代理)
  2. 预分叉tornado应用程序

Tornado 是一个使用 的单线程 Web 服务器 python 模块epoll,它具有内置的预分叉功能(这意味着它将自身生成多个副本作为单独的进程,有效地创建进程池)。Tornado 基于为 Friendfeed 提供动力而创建的技术——他们需要一种方法来处理大量打开的连接,以供长期轮询的客户寻找新的实时更新。

如果您将此作为一个学习过程,那么一定要重新发明!这是一个很好的学习方式。但是如果你真的想在这些东西之上构建一个应用程序,我强烈建议你考虑使用现有的、稳定的、共同开发的项目——它会为你节省很多时间、错误的开始和潜在的陷阱。


(PS我同意你的头像。<3)

于 2011-09-09T07:03:41.063 回答
0

epoll函数(以及同一系列中的其他函数pollselect)允许您编写管理多个网络连接的单线程网络代码。由于没有线程,因此不需要多线程程序中需要的同步(这可能很难做到)。

另一方面,您需要为每个连接提供一个明确的状态机。在线程程序中,此状态机是隐含的。

这些功能只是提供了另一种在一个过程中多路复用多个连接的方法。有时不使用线程更容易,有时您已经在使用线程,因此使用阻塞套接字(在 Python 中释放 GIL)更容易。

于 2011-09-09T07:04:23.683 回答