我应该使用epoll还是仅仅阻止线程中的recv?

dow*_*oad 5 python sockets webserver epoll

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

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

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

现在我听说了epoll,我有点困惑.使用epoll获取套接字数据然后将其直接传递给进程有什么好处?或者我应该按照通常的方式让每个线程等待recv

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

Amb*_*ber 8

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

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

如果你愿意,你可以使用单线程重写你的池进程epoll,这会减少你的整体线程使用数量,但当然你必须考虑这是否是你关心的东西 - 一般来说,低对每个工作者同时发出请求的数量,产生线程的开销并不重要,但是如果你希望每个工作者能够处理1000个开放连接,那么开销就会变得很大(这就是epoll闪耀的地方).

但...

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

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

听起来几乎完全像:

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

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

如果您将此作为一个学习过程,那么一定要重新发明!这是一个很好的学习方式.但是如果你真的想在这些事情之上构建一个应用程序,我强烈建议考虑使用现有的,稳定的,共同开发的项目 - 它会为你节省大量的时间,错误的启动,以及潜在的陷阱.


(PS我赞成你的头像.<3)