本文讨论编写高性能服务器程序时,需要注意的一些问题。
CPU速度与个数、内存大小、固态硬盘、使用GPU。
分配资源,需要花费较多的CPU时间片,有种策略,就是提前预分配好一些资源,并将其放到一个池子中,当需要的时候,直接从池子中拿,用完后,再放入池子中。减少资源分配和释放的时间。
常见的资源分配方案包括:内存池、线程池、进程池、连接池等。 除非内存比较紧张,否则就应该使用预分配资源。【连接池】
在分配内存时,要注意内存对齐。内存对齐,对CPU的影响,比较大。内存对齐函数:posix_memalign(void*p, 16, size)
。
上下文切换(包括进程间、线程间切换),是程序并发性能的真正杀手。过多的切换,会使CPU的资源消耗在上下文切换上,而不是业务处理上。
用vmstate
命令查看cs。
上下文切换的原因:
- (1)活跃线程数 > CPU核心数,活跃的线程越多,上下文切换越频繁。(比较糟糕的设计,一个用户一个线程)
- (2)对请求的处理,从一个线程转移到另外一个线程。(比如用A线程接收用户的请求,之后将请求转给B线程处理,B处理完后,将结果返回给A,这样会增加2次上下文切换)
需要控制好线程的数目(线程数=CPU个数?)
多个线程间共享资源时,需要用到锁,但锁的粒度,很难把握。【同步与锁】
- 粗粒度的锁,会导致并行处理的串行化,降低程序的并发效率,同时可能会导致死锁。
- 细粒度的锁,会频繁的加锁/解锁,消耗程序的CPU,同时会加剧锁的竞争。
- (1)尽量减少锁的使用lock-less。每个线程一份数据拷贝(如线程私有数据),用内存换锁。
- (2)无锁设计lock-free。CAS,即Compare and Swap,这是一个原子操作,Sbinlock的实现需要CAS。
- 数据在内核空间和进程空间之间拷贝时,需要消耗大量的CPU时间(CPU在内核空间和用户空间切换)。 即使在用户空间拷贝数据,也需要花费CPU时间。所以应当尽量避免/减少数据的拷贝。
- 零拷贝。