存储系统02——Libevent事件循环

多路复用(Multiplexing)与多路分解(Demultiplexing)

多路复用(Multiplexing):将多个流合并到一个共享资源(某个线程)中,以便节省系统资源;
多路分解(Demultiplexing):将合并后的流分离成多个原始流,便于后续同步地、有序地处理同时接收的多个请求;

I/O多路复用(I/O Multiplexing)

Linux系统将磁盘、网络等均描述为文件(Everything is File),所以任何形式的I/O都可以称为文件IO;
同时把可以进行I/O操作的内核对象(文件描述符Fd、网络套接字Socket)称为I/O流;

write
read
A
文件
B

阻塞I/O

当有多个进程尝试进行对同一个文件进行I/O操作时,在阻塞I/O方法中,由于每个请求都会阻塞进程/线程,因此需要为每个请求分配独立的进程或线程来处理。在高并发场景下,这种模型会消耗大量系统资源(如内存和上下文切换开销),导致性能瓶颈。

write
write
write
read
A
文件
B
C
D

I/O多路复用

多路:多个I/O请求
复用:通过一个线程监听多个I/O流的就绪状态,而不需要每个I/O流创建单独的线程,从而节省系统资源,多路复用主要有三种:select、poll、epoll;

I/O多路复用本质上还是一种同步I/O,即程序自己执行自己的读写操作,这个过程是阻塞的;而异步I/O则无需自己负责进行读写,进程发起I/O操作后不会被阻塞,内核会负责完成整个 I/O 操作并在完成后通知进程。

Reactor反应堆模式

为了实现事件驱动中将一个或多个客户的服务请求分离(Demultiplexing)和调度(dispatch)给程序,通常采取Reactor反应堆模式;

Reactor反应堆模式是一种用于处理并发 I/O 操作的设计模式,广泛应用于高性能服务器和网络编程中;它通过一个事件循环(Event Loop)和一组事件处理器(Handlers)来高效地处理多个并发事件;Reactor 模式的核心思想是将事件的监听分发和处理分离,从而实现高效的并发处理

工作过程为:一个负责监听和分发事件的事件循环(Event Loop)持续检查事件源(如文件描述符)的状态变化,使用同步事件分离器(Event Demultiplexer)将检测到的事件分发给对应的事件处理器(Event_handler),事件处理器执行完成后,控制权返回到事件循环,继续监听新的事件,重复上述过程。
在这里插入图片描述
Reactor优势:

  1. 通过事件循环和事件处理器的分离,Reactor 模式能够高效地处理多个并发事件,避免了传统阻塞 I/O 模式下的线程阻塞问题;
  2. 事件循环通常运行在单个线程中,减少了线程上下文切换的开销;
  3. 可以通过增加事件处理器来处理更多类型的事件,而无需修改事件循环的逻辑。

Libevent库

Libevent 是一个用 C 语言编写的开源高性能事件通知库,主要设计用于处理网络 I/O 事件、定时事件和信号事件;基于事件循环(Event Loop),当事件(如文件描述符可读、可写、超时等)发生时,自动调用注册的回调函数。

Libevent事件实例(HTTP 服务)

使用 libevent 需要分配一个event_base结构体,每个event_base结构体持有一个事件集合,可以检测有哪些事件发生;event_base可以指定一个I/O多路复用方法(以epoll为例)

  1. 使用event_base_new()函数分配并且返回一个新的具有默认设置的event_base结构体;使用完event_base之后,使用 event_base_free()进行释放。
event_base *base = event_base_new(); // 实例化一个 event_base
.......
if (base)
   event_base_free(base); // 释放指定 event_base
  1. 使用 event_new() 接口注册事件,HTTP服务器可以使用evhttp_new()接口注册evhttp上下文,返回一个被用于监测的文件httpd;使用evhttp_free(httpd)释放事件。
evhttp *httpd = evhttp_new(base); // 创建evhttp上下文
.......
if (httpd)
   evhttp_free(httpd); // 释放指定 evhttp
  1. 创建事件完成后,使用evhttp_set_gencb()接口向事件设定回调函数GenHandler,该回调函数通过读取evhttp中不同的URL请求(Download、Upload、ListShow)并执行对应的操作。
evhttp_set_gencb(httpd, GenHandler, NULL); // 设定回调函数
  1. 当event_base注册了一些事件之后,就需要让 libevent 等待事件并且通知事件的发生;执行循环时,函数重复地检查是否有任何已经注册的事件被触发
event_base_dispatch(base); // 启动事件循环

以上就完成了基于libevent的一个http服务,完整代码如下:

// 初始化和启动一个基于 libevent 和 evhttp 的 HTTP 服务
bool RunModule()
{
	// 初始化环境
    event_base *base = event_base_new();
            
    // 设置监听的端口和地址
    sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(server_port_);
            
    // http 服务器,创建evhttp上下文
    evhttp *httpd = evhttp_new(base);
            
    // 绑定端口和ip
    evhttp_bind_socket(httpd, "0.0.0.0", server_port_) // 将 HTTP 服务器绑定到指定的 IP 地址和端口
            
    // 设定回调函数
    evhttp_set_gencb(httpd, GenHandler, NULL);
            
    // 使用 event_base_dispatch 启动事件循环,开始处理事件
     event_base_dispatch(base)
            
    // 释放释放事件
    if (base) event_base_free(base);
    if (httpd) evhttp_free(httpd);
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值