今天主要给大家分享一下基于非阻塞IO的TCP网络服务程序的线程池模式。
有过网络服务通信经验的人都知道,无论服务端怎么架构,始终要通过socket创建,端口绑定,端口监听,然后进入accept的阶段。伪代码:
int socksvr=socket(para,para,para);
bind(socksvr,addr,sizeof(addr));
listen(socksvr,MAX_PENDING);
while(1){
int sockclt=accept(socksvr,para,para);
create_pthread(para,para,);
if(exit) break;
}
通常上面的这段代码都是放在主线程里面,代码里面创建的线程为工作线程,这段代码里面也采用了多线程,但是能够解决大多数场景,但是当客户端短时间大量的连接上来的时候,由于创建线程比较耗时,因此在一轮循环里耗时较多,就可能会导致客户端超时,连接失败。同时由于客户端多了,那么创建的线程也比较多,多线程之间调度也耗费时间,所以这种架构就只能解决普通的业务量,应对不了高并发和大量的长连接。通常应对高并发都是采用线程池的模式,几乎现在所有的网络服务程序都会采用线程池,但是为什么有的应用服务比较好,自己平时写的应用怎么就不稳定,应对不了高并发呢。这个问题主要就是线程池的设计结构导致的。当然我们自己没有经验的时候,设计的线程池实际上都很差。
leader-follower模式实际上就是线程池调度模式,它主要体现为我们在对线程的调度的时候的一种方式。这种模式其实在一些生意比较火爆的小饭店用的比较多。做个类比,我们去饭店吃饭的时候,首先是进入饭店,然后服务员接待我们,然后向服务员点菜。而客户端连接服务端,流程也是这样的,客户端到了,服务端通过accept进行接待,然后通过recv接受数据,然后开始进行处理。所以我们在饭店就会看到两种模式接待模式,第一种就是在大门口有一个迎宾小姐,你到了然后他就说欢迎光临,然后你就自己走到店里面去坐着,然后在走过来一个服务员让我们点菜,其实这就是传统的线程池模式,伪代码如下:
while(1){
int sockclt=accept(socksvr,para,para);
get_pthread_from_pool(para,para,);
if(exit) break;
}
void doThing(){
waitBecomeLeader();
int sockclt=accept(socksrv,,,);
recv(data,,)
sendDataToBackEnd(data,this);
pushToPool(this);
}
};
class ThreadPool{
void run(){
Thread* th=getLeaderThreadFromPool();
th->doThing();
}
};
ThreadPool pool;
pool.run();
后记
当然一个网络服务要做到稳定,高效,肯定需要各个方面的去进行设计,今天只是简单的从多线程的角度进行了一点好的设计的分享,实际上还有内存池,阻塞非阻塞方面进行设计。我相信一句话,高效稳定的服务不是调试出来的,而是靠设计出来的。