记录一下io多路复用相关笔记
发布时间 2023-07-07 00:16:04作者: Death-Satan
记录一下io多路复用的相关笔记
什么是io多路复用
I/O多路复用(I/O Multiplexing) 是一种并发编程技术,通过使用某种机制使得程序能够同时监听和处理多个I/O事件 它允许单个线程处理多个I/O操作,并在有事件就绪时进行相应的操作,而不需要为每个操作创建一个独立的线程。
- 在I/O多路复用中,可以将多个I/O操作添加到一个"多路复用器"中,常见的多路复用器有
select poll epoll等。多路复用器会监听I/O操作,一旦其中任何一个操作有数据可读、可写或出现异常等就绪事件时,多路复用器将通知程序进行相应的处理
- 当程序调用多路复用器的等待函数时,它会阻塞在那里,直到任何一个I/O操作有事件就绪。一旦有事件就绪,多路复用器将返回哪些操作就绪以及就绪事件的类型,然后程序就可以根据具体事件类型进行相应的读取、写入或其他操作。
I/O多路复用的优势 可以使用更少的线程或进程来处理大量的I/O操作,从而减少了线程切换和资源消耗 相比于传统的一对一的I/O处理方式,它可以提高系统的并发处理能力和资源利用率,特别适用于需要处理大量并发连接或I/O操作的场景,如网络服务器。
总结来说,I/O多路复用是一种通过使用多路复用器来同时管理多个I/O操作的技术,提高程序的并发性和资源利用率。
io多路复用出现的原因和应用场景
I/O多路复用的出现是为了解决传统的一对一的I/O处理方式在大规模并发情况下存在的性能问题。
传统的一对一的I/O处理方式存在以下问题
系统开销大 每个I/O操作都需要创建一个独立的线程或进程来处理,频繁地创建和销毁线程会消耗大量的系统资源,并且切换线程的代价较高。
资源利用率低 由于每个线程或进程只能处理一个I/O操作,在大量并发的情况下,会导致有很多线程或进程处于等待状态,造成资源的低效利用。
扩展性差 当并发量增加时,需要管理的线程或进程数量也呈指数级增长,导致系统无法有效扩展,限制系统的并发能力。
而I/O多路复用机制的优势包括:
资源利用率高 I/O多路复用可以将多个I/O操作集中在一个线程中,并以非阻塞的方式同时监听多个I/O事件。这样可以减少线程或进程的数量,提高系统资源的利用效率。
系统开销低 相比于每个I/O操作都创建一个线程或进程,使用I/O多路复用可以减少创建和销毁线程的开销,降低系统开销。
可扩展性好 使用I/O多路复用可以有效地管理大量并发的I/O操作,使系统能够更好地扩展,处理更多的并发连接。
应用场景:
网络编程 在网络服务器中,常常需要同时监听多个客户端的连接请求,以及处理已连接客户端的读写操作。使用I/O多路复用可以简化服务器编程模型,提高服务器的并发处理能力。
高性能服务器 对于需要处理大量并发连接的高性能服务器,如Web服务器、消息队列服务器等,使用I/O多路复用可以减少线程或进程的数量,提高服务器的性能和扩展性。
异步编程 在异步编程中,使用I/O多路复用可以实现事件驱动的程序设计,通过监听多个I/O事件,以非阻塞的方式处理事件就绪的情况,提高程序的响应速度和并发处理能力。
几种常见I/O多路复用的方式
select
优点
跨平台支持 select 可以在多种操作系统上使用,包括 Windows、Linux 和 macOS 等。
简单易用 select 的接口相对简单,易于理解和使用。
支持大量文件描述符 select 使用位图来表示需要监听的文件描述符集合,理论上可以支持较大数量的文件描述符。
缺点
低效 select 每次调用时需要将所有待监听的文件描述符从用户态拷贝到内核态,这个拷贝操作在文件描述符数量较多时会导致性能下降。
不支持动态增减 一旦设置好了监听的文件描述符集合,就不能动态地增加或删除文件描述符,需要重新设置。
无法知道具体引起事件的文件描述符 当有多个文件描述符就绪时,select 只能返回哪些集合中存在就绪事件,无法直接得知是哪些文件描述符触发了事件。
应用场景
文件传输服务器 当需要同时处理大量客户端请求时,可以使用 select 实现高并发的文件传输服务器。
聊天室或即时通讯应用 通过 select 监听多个客户端的连接和消息读写事件,实现实时的消息传递。
注意事项
文件描述符集合大小限制 不同操作系统对于 select 的文件描述符集合大小有一定限制,需要注意这个限制,避免超出限制导致错误。
阻塞与非阻塞模式 select 适用于同时监听多个文件描述符的读写事件,需要将文件描述符设置为非阻塞模式以避免阻塞整个进程。
避免频繁调用 由于每次调用 select 都要进行拷贝操作,频繁调用 select 可能会导致性能下降,需要合理控制调用频率。
主要步骤或流程
准备文件描述符集合 将所有需要监听的文件描述符添加到 select 的读集合、写集合和异常集合中。
调用 select 等待事件 使用 select 监听文件描述符集合上的事件,当有事件就绪时返回。
处理就绪事件 遍历就绪事件集合,根据事件类型进行相应的处理操作。
poll
优点
跨平台支持 与 select 类似,poll 也可以在多种操作系统上使用。
简单易用 相较于 select,poll 的接口更加简洁,使用起来更加方便。
没有文件描述符数量限制 poll 使用 pollfd 结构体数组来存储待监听的文件描述符和事件类型,没有像 select 那样的位图限制,可以支持较大数量的文件描述符。
缺点
效率不高 与 select 类似,每次调用 poll 也需要将所有待监听的文件描述符从用户态拷贝到内核态,效率较低。
不支持动态增减 与 select 类似,一旦设置好了监听的文件描述符集合,就不能动态地增加或删除文件描述符,需要重新设置。
无法知道具体引起事件的文件描述符 与 select 类似,当有多个文件描述符就绪时,poll 只能返回哪些文件描述符就绪,无法直接得知是哪些文件描述符触发了事件。
应用场景
网络服务器 poll 可以用于实现并发处理多个客户端连接的网络服务器,适用于中小规模的并发需求。
实时数据监控 当需要监听多个实时数据源的变化时,可以使用 poll 来监听这些数据源的事件,并及时处理。
注意事项
文件描述符集合大小限制 不同操作系统对于 poll 的文件描述符集合大小有一定限制,需要注意这个限制,避免超出限制导致错误。
阻塞与非阻塞模式 poll 适用于同时监听多个文件描述符的读写事件,需要将文件描述符设置为非阻塞模式以避免阻塞整个进程。
避免频繁调用 由于每次调用 poll 都要进行拷贝操作,频繁调用 poll 可能会导致性能下降,需要合理控制调用频率。
主要步骤或流程
准备文件描述符集合 将所有需要监听的文件描述符和事件类型添加到 pollfd 结构体数组中。
调用 poll 等待事件:使用 poll 监听文件描述符集合上的事件,当有事件就绪时返回。
处理就绪事件 遍历就绪事件集合,根据事件类型进行相应的处理操作。
总的来说,poll 是一种简单实用的 I/O 多路复用机制,适用于中小规模的并发场景,如果需要更高的性能和更大规模的并发支持,可以考虑使用更现代的机制如 epoll(Linux)或 kqueue(BSD)。
epoll
优点
高效 epoll 使用事件驱动模型,在等待事件时不需要将所有文件描述符拷贝到内核态,只需将就绪的文件描述符添加到内核事件表中,因此在较大规模并发情况下具有更好的性能。
支持动态增减 epoll 提供了 EPOLL_CTL_ADD、EPOLL_CTL_MOD 和 EPOLL_CTL_DEL 等接口,可以动态地增加或删除需要监听的文件描述符。
有效处理大量文件描述符 epoll 可以应对大数量级的文件描述符,通过使用红黑树或哈希表数据结构,避免了 select 和 poll 中位图的限制。
缺点
仅适用于部分操作系统 epoll 主要用于 Linux 操作系统,无法直接在其他操作系统上使用。
编程模型复杂 与 select 和 poll 相比,epoll 的编程模型稍复杂,需要掌握更多的接口和相关知识。
应用场景
高性能网络服务器 epoll 适用于需要处理大量并发连接的网络服务器,例如 Web 服务器、游戏服务器等。
实时数据处理 当需要实时监测文件、设备或传感器等数据源的变化时,epoll 可以高效处理这些事件。
注意事项
系统资源限制 epoll 需要占用较多的系统资源,包括内存和文件描述符。应注意系统的资源限制,避免超出系统容量。
文件描述符限制 操作系统对于单个进程能打开的文件描述符数量有一定限制,需要根据需求配置适当的文件描述符数量。
边缘触发与水平触发模式 epoll 可以设置为边缘触发(EPOLLET)或水平触发(默认模式),在使用时需要理解两种模式的区别和适用场景。
及时移除不再需要监听的文件描述符 当某个文件描述符不再需要被监听时,应及时从 epoll 中删除,避免资源浪费。
主要步骤或过程
创建 epoll 实例 通过 epoll_create 或 epoll_create1 函数创建一个 epoll 实例。
添加文件描述符 使用 epoll_ctl 函数将需要监听的文件描述符添加到 epoll 实例中。
等待事件 使用 epoll_wait 函数等待事件发生,阻塞直到有事件就绪。
处理就绪事件 遍历就绪事件集合,根据事件类型进行相应的处理操作。
kqueue
优点
高效 kqueue 使用事件驱动模型,可以高效地处理大量并发连接和事件。
简洁高效 相较于 select 和 epoll,kqueue 提供了更简洁、易用的接口,并且具有更好的性能表现。
支持多种事件类型 kqueue 支持多种事件类型,包括读取、写入、错误等,可以满足不同场景下的需求。
缺点
仅适用于 BSD 系统 kqueue 主要用于 BSD 系统(例如 FreeBSD、Mac OS 等),无法直接在其他操作系统上使用。
学习成本较高 kqueue 的编程模型需要理解和掌握,比较复杂,可能对开发人员的学习成本有一定要求。
应用场景
高性能服务器 kqueue 在高性能服务器中广泛应用,特别适合需要高并发和实时事件处理的场景。
文件系统监控 kqueue 可以用于监控文件系统的变化,例如监测文件或目录的创建、修改和删除等事件。
实时通信 kqueue 可以用于实现实时通信的服务器或客户端,例如聊天应用、实时游戏等。
注意事项
文件描述符限制 操作系统对于单个进程能打开的文件描述符数量有一定限制,需要根据需求配置适当的文件描述符数量。
系统资源限制 kqueue 需要占用一定的系统资源,包括内存和文件描述符。应注意系统的资源限制,避免超出系统容量。
注意事件处理顺序 kqueue 返回的就绪事件可能不是按照顺序进行处理的,需要合理设计程序结构,保证正确处理事件。
及时关闭无用文件描述符 当某个文件描述符不再需要被监听时,应及时关闭它,避免资源浪费。
主要步骤或流程
创建 kqueue 实例 使用 kqueue 函数创建一个 kqueue 实例。
添加文件描述符 使用 kevent 函数将需要监听的文件描述符和事件类型添加到 kqueue 实例中。
等待事件 使用 kevent 函数等待事件发生,阻塞直到有事件就绪。
处理就绪事件 遍历就绪事件集合,根据事件类型进行相应的处理操作。
总结
- select 适用于简单的并发场景,当需要跨平台支持且并发量不是非常高时,可以选择使用 select 来实现I/O多路复用。但在高性能和大规模并发场景下,更加现代化的机制如 epoll 或 kqueue 可能更合适。
- poll 是一种简单实用的 I/O 多路复用机制,适用于中小规模的并发场景,如果需要更高的性能和更大规模的并发支持,可以考虑使用更现代的机制如 epoll(Linux)或 kqueue(BSD)
- epoll 是功能强大且高性能的 I/O 多路复用机制,适用于需要处理高并发连接和实时事件的场景。但要注意在使用过程中合理管理资源,并理解边缘触发和水平触发模式的区别
- kqueue 是在 BSD 系统中使用的高性能 I/O 多路复用机制,适用于需要处理高并发连接和实时事件的场景,尤其是在 BSD 环境下。但要注意系统资源和文件描述符的限制,并理解事件处理的顺序和时机