记录一下io多路复用相关笔记
记录一下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 环境下。但要注意系统资源和文件描述符的限制,并理解事件处理的顺序和时机
世人慌慌张张,不过图碎银几两