常见的并发网络服务程序设计方案总结

0.非并发

while(1)
{
	clientsock=accept();
	while(1)
	{
		str=recv.clientsock() //block
		if(str)
			send.clientsock(str);
		else
		{
			close(clientsock);
			break;
		}	
	}
}

一次只服务一个客户,阻塞在recv上,浪费时间。

1.process-per-connection

适合长连接,而且计算相应的工作量远远大于fork(),比如数据库服务器。
做法为只要收到一个连接就fork一个子进程,让子进程来处理这个连接,执行handler程序。

2.thread-per-connection

上一个的线程版。开销依然不适合短连接使用,而且收到系统中线程数上限的限制。

3.perfork

对1的优化,见UNP

4.perthread

对2的优化,见UNP

以上五种都是阻塞式网络编程,一般程序都会阻塞在read上,解决方法有两种

  • 用两个线程/进程,一个用来读一个用来写(分离IO)
  • I/O复用(这里涉及两个问题,非阻塞IO和应用层buffer)

5.基本的单线程Rector

I/O和事件处理都在同一个线程中完成,这个线程做着 POLL->READ ACTIVE CHANNEL->DEAL CHANNEL->POLL 的循环,与普通multiplexing的区别在于把业务逻辑部分分离出来。

6.Rector+thread per task

在Rector的基础上,收到请求后创建一个新的线程去计算,这样分离了I/O线程和工作线程,但还是有创建和销毁线程所造成的额外开销,而且不保证返回请求的顺序(比如同一个连接中有多个请求的情况)。

7.Rector+work thread

在6的基础上改为分配一个线程去处理一个连接上的所有请求,这样可以保证不会乱序返回。

8.Rector+Thread pool

引入线程池解决线程创建个销毁的开销。不过这种方法对I/O突发的适应力不强,一个Rector可能处理不过来。

9.Main Rector+Sub Rector

每个Sub Rcetor上都执行5中的操作,但是对突发计算的适应力不强,本质上类似于单线程,因为一个连接由一个Sub Rector全权处理,单个连接上的计算任务并没有做到并发处理。

扫描二维码关注公众号,回复: 5678493 查看本文章

10.one loop per thread + thread pool

8,9的结合,Main Rector 负责接收新连接,并且分发给Sub Rector 处理,Sub Rector们共用Thread Pool,这样对于突发I/O和突发计算都有一定的适应能力。

猜你喜欢

转载自blog.csdn.net/qq_33113661/article/details/88532166