Reactor模式处理高并发

1、epoll的同步编程方式
如果是listenfd,那么放入epoll继续监听
如果是可读fd,那么读取fd,并且处理读时间
int main(int argc, char** argv)
{
epoll_ctr(efd, ADD, fd);

while(1)
{
	epoll_wait(, event, ....);
	for(;;)
	{
		if(fd == listenr_scoket)
		{
			cfd = accept(...);
			epoll_ctr(efd, ADD, cfd);
		}
		else
		{
			read(fd, buf, size);//缺点2:对于所有的客户端的请求处理,变成了一种串行化的处理,如果某个请求很耗时,那么后面的请求势必阻塞起来,那么响应时间会变得很长。
			process(buf);
		}
	}
}

}

以上架构的缺点:
缺点:
1、所有的处理,都是epoll的线程里,会带来很大的压力(网络IO的压力)

半异步半同步编程

T1线程:

while(1)
{
epoll_wait(…)
for(;😉
{
if (fd == listenner_socket)
{
cfd = accpt(listenner_socket);
}
else
{
read(fd, buf, size);
enqueue(buf);
}
}
}
T2线程:

while (1)
{
wait_queue(buf);
process(buf);
}
示例如:
TODO

缺点:
1)线程间需要同步;
2)线程间有数据的拷贝(memcpy),这个拷贝也是很耗CPU的;
3)epoll所在的线程要处理所有的网络IO的读和写,这个线程的压力远远超过其余的业务处理线程。

纯异步 – Reactor设计

先来看libevent库

https://github.com/zhiyong0804/libevent_helloworld/blob/master/libevent_server.c

Reactor设计模式
在这里插入图片描述

Handles :表示操作系统管理的资源,我们可以理解为fd。
Synchronous Event Demultiplexer :同步事件分离器,阻塞等待Handles中的事件发生。
Initiation Dispatcher :初始分派器,作用为添加Event handler(事件处理器)、删除Event handler以及分派事件给Event handler。也就是说,Synchronous Event Demultiplexer负责等待新事件发生,事件发生时通知Initiation Dispatcher,然后Initiation Dispatcher调用event handler处理事件。
Event Handler :事件处理器的接口
Concrete Event Handler :事件处理器的实际实现,而且绑定了一个Handle。因为在实际情况中,我们往往不止一种事件处理器,因此这里将事件处理器接口和实现分开,与C++、Java这些高级语言中的多态类似。
Reactor与多线程的结合

可以参考EasyDarwin里使用Reactor设计模式与多线程的结合
reactor与线程结合

优点:
1)epoll_wait说在的线程只需要监听网络的事件发生,如socket的可读可写事件(EV_RE / EV_WR)然后封装成一个event,继而封装到一个Task。
2)把这个Task按照某种策略(轮询式的负载均衡或者固定到某个线程)压入线程池中某个线程的任务队列里,平摊了IO的性能和处理请求的均衡,提升总体效率;
3)设计变得更加具有模块化和可扩展性,对epoll反应堆没有任何影响;
4)并发实现,如果线程再设置CPU的亲缘性,则更加提高了网络性能。

另外一种架构是
epoll_wait将事件放入队列,然后让其他线程来取,让线程处理事件。

两种架构哪种效率高。
第一种会好:优点:一个是多CPU平摊网络IO,2可扩展性比较强

展开阅读全文

没有更多推荐了,返回首页