es6处理组件复用 react
2017-01-18 11:52:16 omashion 阅读数 70

I/O复用,select和Reactor模式,各自的概念其间的关系,以及最重要的,他们的优势在哪,与同类相比为什么能具有这样的优势。这就是写这篇文字最初的出发点。

I/O复用

I/O复用属于I/O模型中的一种: 
1. 阻塞式I/O: 
这里写图片描述 
2. 非阻塞式I/O: 
这里写图片描述 
3. I/O复用模型 
这里写图片描述 
4. 信号驱动式I/O模型 
这里写图片描述 
5. 异步I/O模型 
这里写图片描述 
以上各个模型之间的比较如下: 
这里写图片描述

select

select 是C语言中的函数,相对于诸如connect、accept、recv或recvfrom这样的阻塞程序来说,使用select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。

监视(多个)文件描述符的变化情况就是select实现I/O复用的方式。任何一个可读、可写或异常都能唤醒select函数的当前进程继续工作,减少了进程阻塞的时间。

所以说,select的主要业务在于设置对一个或多个对象的监听,将所有的阻塞事件集中处理,一旦任一可用,即唤醒进程,多个本应在各自进程上执行的I/O被复用到一个进程中协调执行,达到I/O复用。 
这里写图片描述

Reactor模式

意图

在事件驱动的应用中,将一个或多个客户的服务请求分离(demultiplex)和调度(dispatch)给应用程序。

问题

在分布式系统尤其是服务器这一类事件驱动应用中,虽然这些请求最终会被序列化地处理,但是必须时刻准备着处理多个同时到来的服务请求。在实际应用 中,这些请求总是通过一个事件(如CONNECTOR、READ、WRITE等)来表示的。在有序地处理这些服务请求之前,应用程序必须先分离和调度这些同时到达的事件。为了有效地解决这个问题,我们需要做到以下4方面:

  • 为了提高系统的可测量性和反应时间,应用程序不能长时间阻塞在某个事件源上而停止对其他事件的处理,这样会严重降低对客户端的响应度。
  • 为了提高吞吐量,任何没有必要的上下文切换、同步和CPU之间的数据移动都要避免。
  • 引进新的服务或改良已有的服务都要对既有的事件分离和调度机制带来尽可能小的影响。
  • 大量的应用程序代码需要隐藏在复杂的多线程和同步机制之后。

解决方法

在一个或多个事件源上等待事件的到来,例如,一个已经连接的Socket描述符就是一个事件源。将事件的分离和调度整合到处理它的服务中,而将分离和调度机制从应用程序对特定事件的处理中分离开,也就是说分离和调度机制与特定的应用程序无关。

具体来说,每个应用程序提供的每个服务都有一个独立的事件处理器与之对应。由事件处理器处理来自事件源的特定类型的事件。每个事件处理器都事先注册 到Reactor管理器中。Reactor管理器使用同步事件分离器在一个或多个事件源中等待事件的发生。当事件发生后,同步事件分离器通知 Reactor管理器,最后由Reactor管理器调度和该事件相关的事件处理器来完成请求的服务。

结构

在Reactor模式中,有5个关键的参与者。

  1. 描述符(handle):由操作系统提供,用于识别每一个事件,如Socket描述符、文件描述符等。在Linux中,它用一个整数来表示。事件可以来自外部,如来自客户端的连接请求、数据等。事件也可以来自内部,如定时器事件。
  2. 同步事件分离器(demultiplexer):是一个函数,用来等待一个或多个事件的发生。调用者会被阻塞,直到分离器分离的描述符集上有事件发生。Linux的select函数是一个经常被使用的分离器。
  3. 事件处理器接口(event handler):是由一个或多个模板函数组成的接口。这些模板函数描述了和应用程序相关的对某个事件的操作。
  4. 具体的事件处理器:是事件处理器接口的实现。它实现了应用程序提供的某个服务。每个具体的事件处理器总和一个描述符相关。它使用描述符来识别事件、识别应用程序提供的服务。
  5. Reactor 管理器(reactor):定义了一些接口,用于应用程序控制事件调度,以及应用程序注册、删除事件处理器和相关的描述符。它是事件处理器的调度核心。 Reactor管理器使用同步事件分离器来等待事件的发生。一旦事件发生,Reactor管理器先是分离每个事件,然后调度事件处理器,最后调用相关的模 板函数来处理这个事件。

    通过上述分析,我们注意到,是Reactor管理器而不是应用程序负责等待事件、分离事件和调度事件。实际上,Reactor管理器并没有被具体的 事件处理器调用,而是管理器调度具体的事件处理器,由事件处理器对发生的事件做出处理。这就是类似Hollywood原则的“反向控制”。应用程序要做的 仅仅是实现一个具体的事件处理器,然后把它注册到Reactor管理器中。接下来的工作由管理器来完成。这些参与者的相互关系如下图所示。

这里写图片描述

I/O复用,select和reactor

select是reactor设计模式中的一个组件,也可以说是最核心的组件,为整个模块提供注册事件和监听事件的功能,从另一个的角度来说就是事件的派发,他将可能引起的阻塞等待集中到自身这一个地方进行协调处理,可以实现在单个进程中高效的I/O复用。

如此一来,reactor模式就为服务器处理多个请求提供了一个新的思路——我们不一定非要依靠多个线程来处理,而且多线程之间的频繁切换所带来的系统开销也是非常巨大的。相比之下,表面上看起来多做了好多无谓工作的select操作在具体的应用中会带来更好的效果。而其具体优势可参考上文“Reactor模式”中的“问题”一栏。

es6处理组件复用 react 相关内容

2016-05-07 23:43:59 u012515877 阅读数 2377

I/O复用,select和Reactor模式,各自的概念其间的关系,以及最重要的,他们的优势在哪,与同类相比为什么能具有这样的优势。这就是写这篇文字最初的出发点。

I/O复用

I/O复用属于I/O模型中的一种:
1. 阻塞式I/O:
这里写图片描述
2. 非阻塞式I/O:
这里写图片描述
3. I/O复用模型
这里写图片描述
4. 信号驱动式I/O模型
这里写图片描述
5. 异步I/O模型
这里写图片描述
以上各个模型之间的比较如下:
这里写图片描述

select

select 是c语言中的函数,相对于诸如connect、accept、recv或recvfrom这样的阻塞程序来说,使用select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。

监视(多个)文件描述符的变化情况就是select实现I/O复用的方式。任何一个可读、可写或异常都能唤醒select函数的当前进程继续工作,减少了进程阻塞的时间。

所以说,select的主要业务在于设置对一个或多个对象的监听,将所有的阻塞事件集中处理,一旦任一可用,即唤醒进程,多个本应在各自进程上执行的I/O被复用到一个进程中协调执行,达到I/O复用。
这里写图片描述

Reactor模式

意图

在事件驱动的应用中,将一个或多个客户的服务请求分离(demultiplex)和调度(dispatch)给应用程序。

问题

在分布式系统尤其是服务器这一类事件驱动应用中,虽然这些请求最终会被序列化地处理,但是必须时刻准备着处理多个同时到来的服务请求。在实际应用 中,这些请求总是通过一个事件(如CONNECTOR、READ、WRITE等)来表示的。在有序地处理这些服务请求之前,应用程序必须先分离和调度这些同时到达的事件。为了有效地解决这个问题,我们需要做到以下4方面:

  • 为了提高系统的可测量性和反应时间,应用程序不能长时间阻塞在某个事件源上而停止对其他事件的处理,这样会严重降低对客户端的响应度。
  • 为了提高吞吐量,任何没有必要的上下文切换、同步和CPU之间的数据移动都要避免。
  • 引进新的服务或改良已有的服务都要对既有的事件分离和调度机制带来尽可能小的影响。
  • 大量的应用程序代码需要隐藏在复杂的多线程和同步机制之后。

解决方法

在一个或多个事件源上等待事件的到来,例如,一个已经连接的Socket描述符就是一个事件源。将事件的分离和调度整合到处理它的服务中,而将分离和调度机制从应用程序对特定事件的处理中分离开,也就是说分离和调度机制与特定的应用程序无关。

具体来说,每个应用程序提供的每个服务都有一个独立的事件处理器与之对应。由事件处理器处理来自事件源的特定类型的事件。每个事件处理器都事先注册 到Reactor管理器中。Reactor管理器使用同步事件分离器在一个或多个事件源中等待事件的发生。当事件发生后,同步事件分离器通知 Reactor管理器,最后由Reactor管理器调度和该事件相关的事件处理器来完成请求的服务。

结构

在Reactor模式中,有5个关键的参与者。

  1. 描述符(handle):由操作系统提供,用于识别每一个事件,如Socket描述符、文件描述符等。在Linux中,它用一个整数来表示。事件可以来自外部,如来自客户端的连接请求、数据等。事件也可以来自内部,如定时器事件。
  2. 同步事件分离器(demultiplexer):是一个函数,用来等待一个或多个事件的发生。调用者会被阻塞,直到分离器分离的描述符集上有事件发生。Linux的select函数是一个经常被使用的分离器。
  3. 事件处理器接口(event handler):是由一个或多个模板函数组成的接口。这些模板函数描述了和应用程序相关的对某个事件的操作。
  4. 具体的事件处理器:是事件处理器接口的实现。它实现了应用程序提供的某个服务。每个具体的事件处理器总和一个描述符相关。它使用描述符来识别事件、识别应用程序提供的服务。
  5. Reactor 管理器(reactor):定义了一些接口,用于应用程序控制事件调度,以及应用程序注册、删除事件处理器和相关的描述符。它是事件处理器的调度核心。 Reactor管理器使用同步事件分离器来等待事件的发生。一旦事件发生,Reactor管理器先是分离每个事件,然后调度事件处理器,最后调用相关的模 板函数来处理这个事件。

    通过上述分析,我们注意到,是Reactor管理器而不是应用程序负责等待事件、分离事件和调度事件。实际上,Reactor管理器并没有被具体的 事件处理器调用,而是管理器调度具体的事件处理器,由事件处理器对发生的事件做出处理。这就是类似Hollywood原则的“反向控制”。应用程序要做的 仅仅是实现一个具体的事件处理器,然后把它注册到Reactor管理器中。接下来的工作由管理器来完成。这些参与者的相互关系如下图所示。

这里写图片描述

I/O复用,select和reactor

select是reactor设计模式中的一个组件,也可以说是最核心的组件,为整个模块提供注册事件和监听事件的功能,从另一个的角度来说就是事件的派发,他将可能引起的阻塞等待集中到自身这一个地方进行协调处理,可以实现在单个进程中高效的I/O复用。

如此一来,reactor模式就为服务器处理多个请求提供了一个新的思路——我们不一定非要依靠多个线程来处理,而且多线程之间的频繁切换所带来的系统开销也是非常巨大的。相比之下,表面上看起来多做了好多无谓工作的select操作在具体的应用中会带来更好的效果。而其具体优势可参考上文“Reactor模式”中的“问题”一栏。

es6处理组件复用 react 相关内容

2018-12-04 21:30:23 weixin_37098881 阅读数 110

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可扩展性比较强

es6处理组件复用 react 相关内容

2012-04-26 10:59:36 lishuo102 阅读数 801

    使用Reactor框架处理信号;首先从ACE_Event_Handler类派生出一个子类,并实现它的方法handle_signal(),在这个方法中编写信号处理代码;然后,通过两个适当的register_handler()方法中的一个来登记信号事件处理器(新派生出来的类的对象)。

   处理信号的Reactor框架一旦启动起来,当捕捉到信号的时候,信号处理器对象的handle_signal()方法就会被Reactor框架回调,以响应信号的动作。

   在handle_signal()回调方法中,可以调用ACE_Reactor::instance()->notify(ACE_Event_Handler*)回调方法;来通知信号处理器做某件事情。


#include "ace/Reactor.h"

#include "ace/Event_Handler.h"
#include <signal.h>
class SignalHandler : public ACE_Event_Handler
{
    int handle_signal(int signum, siginfo_t * /* = 0 */, ucontext_t * /* = 0 */)
    {
        switch(signum)
        {
        case SIGINT:
            ACE_DEBUG((LM_DEBUG,ACE_TEXT("SIGINT!/n")));
            break;
        case SIGTERM:
            ACE_DEBUG((LM_DEBUG,ACE_TEXT("SIGTERM!/n")));
            break;
        case SIGBREAK:
            ACE_DEBUG((LM_DEBUG,ACE_TEXT("SIGBREAK!/n")));
            break;
        }
        return 0;
    }
};
int ACE_TMAIN(int argc, ACE_TCHAR* argv[])
{
    SignalHandler sh;
    ACE_Reactor::instance()->register_handler(SIGINT,&sh);
    ACE_Reactor::instance()->register_handler(SIGTERM,&sh);
    ACE_Reactor::instance()->register_handler(SIGBREAK,&sh);
    while(1)
    {
        ACE_Reactor::instance()->handle_events();
    }
    return 0;
}

es6处理组件复用 react 相关内容

2014-10-20 14:02:18 zxcbnmlei 阅读数 632

详细说明连接:http://blog.csdn.net/gashero/article/details/1519032


我的test:开启reactor.run(), 每3秒执行main()

from twisted.internet import reactor

import time

def main():
    reactor.callLater(3,main)
    print 'Current time is',time.strftime("%H:%M:%S")

if __name__ == '__main__':
    main()
    reactor.run()

es6处理组件复用 react 相关内容

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