戴利:有没有可能我的反应堆吞吐量有限?我怎么知道呢?io_service的实现有多昂贵和可伸缩性(跨线程)?
我有一个非常大规模的并行应用程序,它运行在一台超线程双四核至强机器上,有大量的RAM和一个快速的SSD RAID。这是使用boost::asio开发的。
这个应用程序接受来自大约1000台其他机器的连接,读取数据,解码简单的协议,并将数据混洗到使用mmap()映射的文件中。这个应用程序还使用sure (WILLNEED)预取“未来的”mmap页面,因此它不太可能在页面错误时阻塞,但为了确认,我已经尝试生成多达300个线程。
它运行在Linux kernel 2.6.32-27-generic (Ubuntu服务器x64 LTS10.04)上。Gcc版本是4.4.3,boost::asio版本是1.40 (都是现货Ubuntu LTS)。
运行vmstat、iostat和top,我看到磁盘吞吐量(以TPS和数据卷为单位)为个位数%。类似地,磁盘队列长度总是比线程数小得多,所以我不认为我有I/O限制。此外,RSS会攀升,但随后会稳定在几个at (正如预期的那样),并且vmstat没有显示分页,所以我认为我不受内存限制。CPU在0-1%的用户上是恒定的,6-7%的系统是恒定的,其余的都是空闲的。线索!一个完整的“核心”(记住超线程)是CPU的6.25%。
我知道系统正在落后,因为客户端机器在超过64kB时阻塞TCP发送,并报告事实;它们都不断报告这一事实,系统的吞吐量远远低于预期的、预期的和理论上可能的。
我的猜测是我在某种锁上争执。我使用应用程序级别的锁来保护可能会发生变化的查找表,因此我将其分成256个顶级锁/表,以打破这种依赖。然而,这似乎一点帮助都没有。
所有线程都通过一个全局io_service实例。在应用程序上运行strace表明,它将大部分时间花在处理futex调用上,我认为这与io_service反应器的基于事件的实现有关。
有没有可能我的反应堆吞吐量有限?我怎么知道呢?io_service的实现有多昂贵和可伸缩性(跨线程)?
编辑:我最初没有找到另一个线程,因为它使用了一组没有与我的线程重叠的标签:-/我的问题很可能是在boost::asio reactor的实现中使用了过多的锁定。参见C++ Socket Server - Unable to saturate CPU然而,问题仍然存在:我如何证明这一点?我怎么才能修复它呢?
发布于 2011-08-25 14:13:45
答案确实是,即使是最新的boost::asio也只从单个线程调用epoll文件描述符,而不是同时从多个线程进入内核。我可以在某种程度上理解为什么,因为当你使用多个线程,每个线程都可以获得相同文件描述符的通知时,对象的线程安全和生存期是非常不稳定的。当我自己编写代码(使用pthread)时,它可以工作,并且可以扩展到单个内核之外。在这一点上没有使用boost::asio --令人遗憾的是,一个设计良好且可移植的库会有这样的限制。
发布于 2011-10-14 04:04:54
我相信如果你使用多个io_service对象(比如每个cpu核心),每个对象都由一个线程运行,你就不会有这个问题。请参阅boost ASIO页面上的http服务器示例2。
我对服务器示例2和服务器示例3进行了各种基准测试,发现我提到的实现效果最好。
发布于 2015-10-31 11:11:56
在我的单线程应用程序中,我通过分析发现很大一部分处理器指令被io_service::poll()用于锁定和解锁。我使用BOOST_ASIO_DISABLE_THREADS宏禁用了锁操作。它可能对您也有意义,这取决于您的线程情况。
https://stackoverflow.com/questions/7052519
复制相似问题