似乎有几个选项可用于处理大量套接字连接的程序(例如 Web 服务、p2p 系统等)。
- 生成一个单独的线程来处理每个套接字的 I/O。
- 使用select将 I/O 多路复用到单个线程中的系统调用。
- 使用poll多路复用 I/O 的系统调用(替换选择)。
- 使用epoll系统调用以避免必须通过用户/系统边界重复发送套接字 fd。
- 生成多个 I/O 线程,每个线程使用轮询 API 多路复用连接总数中相对较小的一组。
- 按照#5 除了使用 epoll API 为每个独立的 I/O 线程创建一个单独的 epoll 对象。
在多核 CPU 上,我希望 #5 或 #6 具有最佳性能,但我没有任何硬数据支持这一点。网上搜索出现this描述作者测试上述方法 #2、#3 和 #4 的经验的页面。不幸的是,该网页似乎已有 7 年历史,没有发现明显的近期更新。
所以我的问题是人们发现这些方法中的哪一种最有效和/或是否有另一种方法比上面列出的任何方法都更有效?对现实生活中的图表、白皮书和/或网络上可用的文章的引用将不胜感激。
最佳答案
根据我运行大型 IRC 服务器的经验,我们曾经使用 select() 和 poll()(因为 epoll()/kqueue() 不可用)。在大约 700 个并发客户端时,服务器将使用 100% 的 CPU(irc 服务器不是多线程的)。然而,有趣的是,服务器仍然会表现良好。在大约 4,000 个客户端时,服务器将开始滞后。
这样做的原因是,在大约 700 个客户端中,当我们返回 select() 时,将有一个客户端可用于处理。 for() 循环扫描以找出哪个客户端会占用大部分 CPU。随着我们的客户越来越多,我们会开始越来越多的客户需要在每次调用 select() 时进行处理,因此我们会变得更有效率。
转向 epoll()/kqueue(),类似规范的机器可以轻松处理 10,000 个客户端,其中一些(不可否认更强大的机器,但按照今天的标准仍然被认为是很小的机器)已经拥有 30,000 个客户端不费吹灰之力。
我在 SIGIO 上看到的实验似乎表明它适用于延迟非常重要的应用程序,在这些应用程序中只有少数事件客户端执行很少的单独工作。
我建议几乎在任何情况下都使用 epoll()/kqueue() 而不是 select()/poll()。我没有尝试在线程之间拆分客户端。老实说,我从来没有发现需要在前端客户端处理上完成更多优化工作才能证明使用线程进行实验的服务。
关于linux - 如何最有效地处理大量文件描述符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/142677/