我目前正在尝试构建一个http服务器.服务器由一个监听线程使用select(...)和由线程池管理的四个工作线程进行多线程处理.我目前在Core I3 330M上每秒管理大约14k-16k的请求,文件长度为70字节,响应时间为6-10ms.但这是没有保持活力和我服务的任何插座我在工作完成时立即关闭.
编辑:工作线程处理在检测到套接字上的活动时调度的"作业",即.服务请求."工作"完成后,如果没有"工作",我们会睡觉,直到发送更多"工作"或者已经有一些工作可用,我们就会开始处理其中一个工作.
当我开始尝试实现keep-alive支持时,我的问题开始了.通过keep-alive激活,我只需要每秒管理1.5k-2.2k请求,并且有100个开放套接字.这个数字增加到大约12k,1000个开放插座.在这两种情况下,响应时间大约为60-90ms.我觉得这很奇怪,因为我目前的假设认为请求应该上升,而不是下降,响应时间应该会下降,但绝对不会上升.
我已经尝试了几种不同的策略来修复低性能:
保持活动套接字存储在一个简单的链接List中,其添加/删除方法由pthread_mutex锁定,负责重建FD_SET的函数也具有此锁定.
我怀疑它是在这里的主要元凶互斥的不断锁定/解锁,我试着来分析这个问题,但没有gprof的还是谷歌perftools一直非常合作,无论是引入极端不稳定或纯拒不收集的任何数据所有(这可能是我不知道如何正确使用这些工具.).但是删除锁可能会使链表处于不合理的状态,并可能导致程序崩溃或将程序置于无限循环中.我在使用它时还怀疑select(...)/ pselect(...)超时,但我非常有信心这不是问题,因为即使没有它也会保持低性能.
我不知道应该如何处理保持活动的套接字,我想知道你们那里的人是否对如何修复低性能有任何建议,或者对我可以用来支持的任何替代方法有任何建议保持活跃的插座.
尽量完全摆脱选择.您可以在每个流行的平台上找到某种事件通知:freebsd()上的kqueue/kevent,Linux上的epoll等.这样您就不需要重建FD_SET并且可以随时添加/删除监视的fds.
当客户端使用您的套接字进行多个请求时,时间的增加将更加明显。如果您只是打开和关闭,但仍然告诉客户端保持活动状态,那么您会遇到与没有保持活动状态相同的情况。但现在套接字的开销仍然存在。
但是,如果您从同一客户端多次使用套接字来处理多个请求,那么您将损失 TCP 连接开销并以这种方式获得性能。
确保您的客户端正确使用 keepalive。这可能是获取套接字状态和数据通知的更好方法。也许是轮询设备或对请求进行排队。
http://www.techrepublic.com/article/using-the-select-and-poll-methods/1044098
此页面有一个用于 Linux 处理轮询设备的补丁。也许对其工作原理有所了解,并且您可以在应用程序中使用相同的技术,而不是依赖于可能未安装的设备。