(一)线程数量与线程池模型
参见:high-performance server design
. http://pl.atyp.us/content/tech/servers.html 频繁的上下文切换,会导致系统性能严重下降,而产生过多的切换大致有两个原因:
1)过多的线程数量。这会使系统性能呈指数级的下降。对于每连接一个线程的系统而言,这也是为什么性能会变差的原因。一个具有可伸缩性的系统,它的唯一可行的选择,就是限制运行线程的数量。一般而言,这个值应该小于或等于处理器的数目。(说明,在boost网络库asio提供的example中,有一个关于这种实现的很好的例子)
2)所使用的线程池及事件模型。最简单的一种模型通常是这个样子:一个侦听线程异步地接收请求,并在队列中进行缓冲。另外一组工作者线程则负责处理这些请求。这是一个不错的模型,缺点就是每处理一个请求一般要经过两次线程切换(加上对请求的回复)。为了避免这种缺点,一个线程就必须具备侦听者和工作者两种角色,可以采用称之谓“领导者/跟随者”的模型。一个线程作为领导者,来进行监听,当收到请求时,它选出一个跟随者线程作为新的领导者进行侦听,自己则对请求进行处理,结束后,到跟随者队列中进行等待。
(二)多线程的内存池优化
普通的内存池一旦应用到多线程中,都面临着锁竞争的问题,在stlport所做的对于字符串性能的测试中,当使用两个线程时,它所使用的内存池node_allocator性能已经出现明显的下降。所以对于多线程而言,一个线程一个内存池是一个很好的选择。要实现这种设计,面临的第一个问题,是内存块的跨线程使用问题,即一个内存块,可能在A线程中申请,但可能在B线程中释放。
在GCC的STL实现libstdc++中,有一个多线程内存池的实现(mt_allocator)。它是node_allocator(现在叫pool_allocator) 的多线程版本。它还有一个优点就是所有参数都是可配置的。
它的设计思路如下:每个线程一个内存池,同时还有一个全局的内存池。每个线程可以访问自己的内存池,同时可在锁保护下访问全局内存池。申请的每一个内存块中,都有一个线程ID,以标明是从哪个线程中申请的。
申请过程:首先向所在线程申请,若本线程没有空闲块,则向全局内存池申请。
释放过程:直接归还到本线程的空闲链中。还有一个问题,为了防止线程内存池之间的不均衡,或者某一个线程中的空闲链过长,可以设置一个水位标,当超过这个水位标时,把释放的内存直接归还到全局内存池中。