thread-based architecture(基于线程)和event-driven architecture(事件驱动)详解

在处理web请求时,通常有两种体系结构,分别为:thread-based architecture(基于线程)、event-driven architecture(事件驱动)。

thread-based architecture

基于线程的体系结构通常会使用多线程来处理客户端的请求,每当接服务端主程序收到一个请求,便开启一个独立的线程来处理客户端的事件。这种方式仅适用于并发访问量不大的场景,因为线程需要占用一定的内存资源,且操作系统在线程之间的切换也需要一定的开销,当线程数过多时显然会降低web服务器的性能。并且线程阻塞等待I/O操作时也会造成CPU资源的浪费。

event-driven architecture

事件驱动体系结构是目前比较广泛使用的一种。这种方式会定义一系列的事件处理器来响应事件的发生,并且将服务端接受连接与对事件的处理分离。其中,事件是一种状态的改变。比如,tcp中socket的new incoming connection、ready for read、ready for write。

reactor

reactor设计模式是event-driven architecture的一种实现方式,处理多个客户端并发的向服务端请求服务的场景。每种服务在服务端可能由多个方法组成。reactor会解耦并发请求的服务并分发给对应的事件处理器来处理。目前,许多流行的开源框架都用到了reactor模式,如:netty、node.js等,包括java的nio。

reactor主要由以下几个角色构成:handle、Synchronous Event Demultiplexer、Initiation Dispatcher、Event Handler、Concrete Event HandlerHandle。

handle
handle在linux中一般称为文件描述符,而在window称为句柄,两者的含义一样。handle是事件的发源地。比如一个网络socket、磁盘文件等。而发生在handle上的事件可以有connection、ready for read、ready for write等。
Synchronous Event Demultiplexer
同步事件分离器,本质上是系统调用。比如linux中的select、poll、epoll等。比如,select方法会一直阻塞直到handle上有事件发生时才会返回。
Event Handler
事件处理器,其会定义一些回调方法或者称为钩子函数,当handle上有事件发生时,回调方法便会执行,一种事件处理机制。
Concrete Event Handler
具体的事件处理器,实现了Event Handler。在回调方法中会实现具体的业务逻辑。
Initiation Dispatcher
初始分发器,也是reactor角色,提供了注册、删除与转发event handler的方法。当Synchronous Event Demultiplexer检测到handle上有事件发生时,便会通知initiation dispatcher调用特定的event handler的回调方法。
处理流程

  1. 当应用向Initiation Dispatcher注册Concrete Event Handler时,应用会标识出该事件处理器希望Initiation Dispatcher在某种类型的事件发生发生时向其通知,事件与handle关联;
  2. Initiation Dispatcher要求注册在其上面的Concrete Event Handler传递内部关联的handle,该handle会向操作系统标识;
  3. 当所有的Concrete Event Handler都注册到 Initiation Dispatcher上后,应用会调用handle_events方法来启动Initiation Dispatcher的事件循环,这时Initiation Dispatcher会将每个Concrete Event Handler关联的handle合并,并使用Synchronous Event Demultiplexer来等待这些handle上事件的发生
  4. 当与某个事件源对应的handle变为ready时,Synchronous Event Demultiplexer便会通知 Initiation Dispatcher。比如tcp的socket变为ready for reading
  5. Initiation Dispatcher会触发事件处理器的回调方法。当事件发生时, Initiation Dispatcher会将被一个“key”(表示一个激活的handle)定位和分发给特定的Event Handler的回调方法;
  6. Initiation Dispatcher调用特定的Concrete Event Handler的回调方法来响应其关联的handle上发生的事件。

实例

下面以一小段swoole的TCP服务器代码为例进一步了解reactor。
三个回调函数connect、receive、close中的参数reactorId表示处理事件的reactor的id

<?php
//创建Server对象,监听 127.0.0.1:9501端口
$serv = new swoole_server("127.0.0.1", 9501);

//监听连接进入事件
$serv->on('connect', function ($serv, $fd, $reactorId) {
    echo "Client connect->".$fd."\n";
    echo "Reactor ID in onConnect is:".$reactorId."\n";
});

//监听数据接收事件
$serv->on('receive', function ($serv, $fd, $reactorId, $data) {
    echo "Reactor ID in onReceive is:".$reactorId."\n";
    $serv->send($fd, "Server: ".$data);
});

//监听连接关闭事件
$serv->on('close', function ($serv, $fd, $reactorId) {
    echo "Reactor ID in onClose is:".$reactorId."\n";
    echo "Client close->".$fd."\n";
});

//启动服务器
$serv->start();

对开几个终端执行 telnet 127.0.0.1 9501 打印结果如下
在这里插入图片描述

参考

https://www.jianshu.com/p/eef7ebe28673

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值