深度剖析并发I/O模型select、poll、epoll与IOCP核心机制

news2025/5/24 19:24:50

核心概要selectpollepollIOCP 是四种用于提升服务器并发处理能力的I/O模型或机制。前三者主要属于I/O多路复用范畴,允许单个进程或线程监视多个I/O流的状态;而 IOCP 则是一种更为彻底的异步I/O模型

一、引言:为何需要这些技术?

在网络服务器开发中,一个核心挑战是如何高效地处理大量并发连接。传统的阻塞式I/O模型(一个线程处理一个连接,并在I/O操作时阻塞)在并发量高时会导致线程数量激增,带来巨大的上下文切换开销和资源消耗。为了解决这一问题,发展出了I/O多路复用和异步I/O技术。

二、I/O多路复用技术:select, poll, epoll

I/O多路复用允许单个进程监视多个文件描述符(FD),一旦某个或某些FD就绪(例如,可读或可写),便通知应用程序进行相应的I/O操作。应用程序本身在调用这些多路复用函数时可能会阻塞,但一旦收到通知,后续的I/O操作(如read, write)通常可以非阻塞地执行,或者至少是已知的可操作状态。

1. select

一句话介绍select 是一种传统的I/O多路复用机制,它允许程序监视一组文件描述符,等待一个或多个描述符变为就绪状态。

工作机制

  • 应用程序通过 fd_set 数据结构向内核注册需要监视的读、写和异常文件描述符集合。

  • 调用 select 函数,该调用会阻塞,直到有文件描述符就绪或超时。

  • select 返回后,内核会修改传入的 fd_set 来指示哪些文件描述符已就绪。

  • 应用程序需要遍历整个 fd_set 来找出具体就绪的文件描述符,并对其进行操作。

主要特点

  • 跨平台性:作为早期标准,select 具有良好的跨平台兼容性。

  • 文件描述符数量限制:受 FD_SETSIZE 宏的限制(通常为1024或2048),能够监视的文件描述符数量有限。

  • 性能开销:

    • 每次调用都需要将 fd_set 在用户空间和内核空间之间完整拷贝。

    • 内核在检查时需要遍历所有被监视的FD。

    • 应用程序在返回后也需要遍历 fd_set 以确定哪些FD就绪。

举例:想象一位老派的邮局分拣员。每次来一批信件(FD集合),他都要把所有信箱(所有被监视的FD)检查一遍,看看哪些信箱里有新信(FD就绪)。即使只有少数信箱有信,他也得全部看一遍。而且他能管理的信箱总数也是固定的

2. poll

一句话介绍pollselect 的一种改进,它解决了文件描述符数量的限制,并使用不同的数据结构来管理监视的描述符。

工作机制

  • 应用程序使用一个 pollfd 结构体数组来指定要监视的文件描述符及其关心的事件(如 POLLIN 表示可读,POLLOUT 表示可写)。

  • 调用 poll 函数,该调用会阻塞,直到有描述符就绪或超时。

  • poll 返回后,内核会在 pollfd 结构体中的 revents 字段中标示出哪些文件描述符发生了哪些事件。

  • 应用程序需要遍历这个 pollfd 数组来找出就绪的描述符。

主要特点

  • 无文件描述符数量硬性限制:监视的FD数量仅受系统资源限制。

  • 数据结构改进:使用 pollfd 结构体,每个结构体对应一个FD,避免了 selectfd_set 的固定大小问题。

  • 性能开销依然存在:

    • 每次调用仍需将 pollfd 数组在用户空间和内核空间之间拷贝。

    • 内核和应用程序仍需遍历所有被监视的FD(即使只有少数就绪)。

3. epoll (Linux Specific)

一句话介绍epoll 是 Linux 内核提供的高效I/O多路复用机制,它显著改善了处理大量并发连接时的性能。

工作机制

epoll 的使用分为三个主要步骤:

  1. epoll_create / epoll_create1:在内核中创建一个 epoll 实例,返回一个代表该实例的文件描述符。

  2. epoll_ctl:向 epoll 实例中添加(EPOLL_CTL_ADD)、修改(EPOLL_CTL_MOD)或删除(EPOLL_CTL_DEL)需要监视的文件描述符及其关心的事件。这些信息由内核维护,不需要重复传递。

  3. epoll_wait:阻塞等待已注册的文件描述符上发生就绪事件。与 selectpoll 不同,epoll_wait 仅返回那些已经就绪的文件描述符,而不是所有被监视的描述符。

主要特点

  • 高效性:

    • 事件驱动:内核负责跟踪FD的状态,当FD就绪时,会将其放入一个就绪列表中。epoll_wait 只需检查此列表。

    • 减少数据拷贝:FD集合由内核管理,epoll_wait 调用时无需拷贝整个FD集合。

    • 无需遍历:应用程序直接从 epoll_wait 的返回中获取就绪的FD列表,避免了轮询。

  • 支持边缘触发 (ET) 和水平触发 (LT):

    • LT (Level Triggered, 默认):只要FD处于就绪状态,epoll_wait 就会通知。

    • ET (Edge Triggered):仅当FD状态从未就绪变为就绪时通知一次。这要求应用程序一次性处理完所有可用数据,编程更复杂,但能进一步减少 epoll_wait 的调用次数。

  • Linux 特有:不具备跨平台性。

举例epoll 就像一个现代化的智能快递柜系统。快递员(内核)把包裹(数据)放进柜子(FD就绪)后,系统会自动给收件人(应用程序)发送一条取件码(epoll_wait 返回就绪的FD)。收件人凭码直接取件,无需检查每个柜子。

三、异步I/O模型:IOCP (Windows Specific)

异步I/O (Asynchronous I/O) 模型与I/O多路复用有本质区别。在异步I/O中,应用程序发起一个I/O操作后立即返回,不等待操作完成。操作系统内核负责完成整个I/O过程(包括将数据从内核空间拷贝到用户指定的缓冲区),并在操作完成后通过特定机制通知应用程序。

IOCP (I/O Completion Ports)

一句话介绍IOCP 是 Windows 平台上一种高效、可伸缩的异步I/O模型,专为处理大量并发I/O操作设计。

工作机制

  1. 创建完成端口:应用程序首先创建一个I/O完成端口 (CreateIoCompletionPort)。

  2. 关联设备句柄:将需要进行异步I/O操作的设备句柄(如套接字、文件句柄)与该完成端口关联。

  3. 发起异步I/O操作:应用程序调用异步I/O函数(如 ReadFile, WriteFile, WSASend, WSARecv),并提供一个 OVERLAPPED 结构和一个可选的完成键。这些函数会立即返回,表示操作已成功提交给操作系统。

  4. 操作系统处理:操作系统内核在后台执行实际的I/O操作。

  5. 完成通知:当I/O操作完成(或失败)后,操作系统会将一个包含操作结果和 OVERLAPPED 结构指针的“完成包”排入与设备句柄关联的完成端口队列中。

  6. 获取完成状态:应用程序的工作线程调用 GetQueuedCompletionStatus 函数,该函数会阻塞等待,直到完成端口队列中有完成包。获取到完成包后,线程便可以处理已完成的I/O操作结果(数据已在用户缓冲区)。

主要特点

  • 真正的异步:应用程序不参与实际的I/O数据传输过程,仅发起请求和处理完成通知。

  • 高效的线程管理IOCP 能够与线程池良好集成。操作系统会根据I/O负载和CPU核心数量智能地调度和唤醒工作线程,避免了过多的线程创建和上下文切换。

  • 高吞吐量和伸缩性:非常适合构建高性能服务器应用。

  • Windows 特有:不具备跨平台性。

举例IOCP 就像一个大型中央厨房的外卖系统。顾客(应用程序)通过App下单(发起异步I/O),然后就可以去做别的事情了。中央厨房(操作系统)负责烹饪并打包(执行I/O)。菜品完成后,系统会通知骑手(工作线程)去指定的取餐点(完成端口)取餐并配送(处理完成的I/O)。骑手们被高效地调度,确保外卖准时送达。


四、总结

特性selectpollepoll (Linux)IOCP (Windows)
模型同步I/O多路复用同步I/O多路复用同步I/O多路复用异步I/O
核心思想监视FD,等待就绪通知监视FD,等待就绪通知高效监视FD,仅返回就绪FD发起I/O,等待操作完成通知
数据传输程序在收到通知后自行读写程序在收到通知后自行读写程序在收到通知后自行读写内核完成数据传输
效率低,受FD数量和轮询限制一般,不受FD数量限制,但仍需轮询高,事件驱动,无需轮询非常高,内核级异步,线程调度优化
跨平台性良好较好差 (Linux)差 (Windows)

选择哪种技术取决于具体的应用场景、目标平台以及对性能和并发能力的要求。对于需要跨平台且并发要求不极端的情况,selectpoll 可能是简单选择。对于Linux平台下追求极致性能的高并发服务器,epoll 是首选。对于Windows平台下的高性能服务器,IOCP 提供了强大的异步处理能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2384825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构 -- 交换排序(冒泡排序和快速排序)

冒泡排序 基于“交换”的排序&#xff1a;根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置 //交换 void swap(int &a,int &b){int temp a;a b;b temp; }//冒泡排序 void BubbleSort(int A[],int n){for(int i0;i<n-1;i){bool flag false; …

【算法】: 前缀和算法(利用o(1)的时间复杂度快速求区间和)

前缀和算法&#xff1a;高效处理区间求和的利器 目录 引言什么是前缀和前缀和的基本实现前缀和的作用前缀和的典型应用场景前缀和的优缺点分析实战例题解析 引言 区间求和问题的普遍性暴力解法的时间复杂度问题前缀和算法的核心思想 什么是前缀和 前缀和的数学定义 通俗来…

macOS 安装 PostgreSQL

文章目录 安装安装信息 验证GUI 工具下载 安装 最简单的方式是通过 brew 安装 brew install postgresql17该版本在 brew 上的详情页&#xff1a;https://formulae.brew.sh/formula/postgresql17 你也可以根据需要&#xff0c;搜索 安装更新版本 如果你没有安装 brew&#xf…

Linux系统:基础命令之 ls~pwd~cd

文章目录 前言一、ls命令&#x1f4d8; 命令简介&#xff1a;&#x1f9e0; 基本语法&#xff1a;演示ls&#x1f527; 常用选项&#xff1a;-l选项-a选项-h选项 小结 ls 二、pwd命令&#x1f4d8; 命令简介&#xff1a;何为绝对路径&#xff01;何为相对路径&#xff01;&…

基于OAuth2-proxy和Keycloak为comfyui实现SSO

背景 comfyui无认证被漏扫后易被rce挖矿 攻击过程 https://www.oschina.net/news/340226 https://github.com/comfyanonymous/ComfyUI/discussions/5165 阿里云漏洞库关于comfyui的漏洞 https://avd.aliyun.com/search?qcomfyui&timestamp__1384n4%2BxBD0GitGQ0QD8ID%2F…

SmartSoftHelp 之 SQL Server 数据库安全备份与安全还原详解---深度优化版:SmartSoftHelp DeepCore XSuite

SmartSoftHelp 菜单之 DBMS 数据库备份与还原 (DBBackRest) 使用实例 SQL Server 数据库备份与还原详解 SQL Server 数据库的备份与还原是管理数据库的核心任务之一&#xff0c;涉及本地与远程操作、大小监控及目录管理等多个方面。以下是详细说明&#xff1a; 一、数据库…

Spring 代理与 Redis 分布式锁冲突:一次锁释放异常的分析与解决

Spring 代理与 Redis 分布式锁冲突&#xff1a;一次锁释放异常的分析与解决 Spring 代理与 Redis 分布式锁冲突&#xff1a;一次锁释放异常的分析与解决1. 问题现象与初步分析2 . 原因探究&#xff1a;代理机制对分布式锁生命周期的干扰3. 问题复现伪代码4. 解决方案&#xff1…

【数据结构】队列的完整实现

队列的完整实现 队列的完整实现github地址前言1. 队列的概念及其结构1.1 概念1.2 组织结构 2. 队列的实现接口一览结构定义与架构初始化和销毁入队和出队取队头队尾数据获取size和判空 完整代码与功能测试结语 队列的完整实现 github地址 有梦想的电信狗 前言 ​ 队列&…

根据YOLO数据集标签计算检测框内目标面积占比(YOLO7-10都适用)

程序&#xff1a; 路径改成自己的&#xff0c;阈值可以修改也可以默认 #zhouzhichao #25年5月17日 #计算时频图中信号面积占检测框面积的比值import os import numpy as np import pandas as pd from PIL import Image# Define the path to the directory containing the lab…

LLM笔记(九)KV缓存(2)

文章目录 1. 背景与动机2. 不使用 KV Cache 的情形2.1 矩阵形式展开2.2 计算复杂度 3. 使用 KV Cache 的优化3.1 核心思想3.2 矩阵形式展开3.3 计算复杂度对比 4. 总结5. GPT-2 中 KV 缓存的实现分析5.1 缓存的数据结构与类型5.2 在注意力机制 (GPT2Attention) 中使用缓存5.3 缓…

LVS 负载均衡集群应用实战

前提:三台虚拟机,有nginx,要做负载 1. LVS-server 安装lvs管理软件 [root@lvs-server ~]# yum -y install ipvsadm 程序包:ipvsadm(LVS管理工具) 主程序:/usr/sbin/ipvsadm 规则保存工具:/usr/sbin/ipvsadm-save > /path/to/file 配置文件:/etc/sysconfig/ipvsad…

MySQL——基本查询内置函数

目录 CRUD Create Retrieve where order by limit Update Delete 去重操作 聚合函数 聚合统计 内置函数 日期函数 字符函数 数学函数 其它函数 实战OJ 批量插入数据 找出所有员工当前薪水salary情况 查找最晚入职员工的所有信息 查找入职员工时间升序排…

Day34打卡 @浙大疏锦行

知识点回归&#xff1a; CPU性能的查看&#xff1a;看架构代际、核心数、线程数GPU性能的查看&#xff1a;看显存、看级别、看架构代际GPU训练的方法&#xff1a;数据和模型移动到GPU device上类的call方法&#xff1a;为什么定义前向传播时可以直接写作self.fc1(x) 作业 计算资…

AdGuard解锁高级版(Nightly)_v4.10.36 安卓去除手机APP广告

AdGuard解锁高级版(Nightly)_v4.10.36 安卓去除手机APP广告 AdGuard Nightly是AdGuard团队为及时更新软件而推出的最新测试版本&#xff0c;适合追求最新功能和愿意尝试新版本的用户。但使用时需注意其潜在的不稳定性和风险。…

C++修炼:红黑树的模拟实现

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

基于Python+YOLO模型的手势识别系统

本项目是一个基于Python、YOLO模型、PyQt5的实时手势识别系统&#xff0c;通过摄像头或导入图片、视频&#xff0c;能够实时识别并分类不同的手势动作。系统采用训练好的深度学习模型进行手势检测和识别&#xff0c;可应用于人机交互、智能控制等多种场景。 1、系统主要功能包…

自制操作系统day10叠加处理

day10叠加处理 叠加处理&#xff08;harib07b&#xff09; 现在是鼠标的叠加处理&#xff0c;以后还有窗口的叠加处理 涉及图层 最上面小图层是鼠标指针&#xff0c;最下面的一张图层用来存放桌面壁纸。移动图层的方法实现鼠标指针的移动以及窗口的移动。 struct SHEET { u…

鸿蒙Flutter实战:23-混合开发详解-3-源码模式引入

引言 在前面的文章混合开发详解-2-Har包模式引入中&#xff0c;我们介绍了如何将 Flutter 模块打包成 Har 包&#xff0c;并引入到原生鸿蒙工程中。本文中&#xff0c;我们将介绍如何通过源码依赖的方式&#xff0c;将 Flutter 模块引入到原生鸿蒙工程中。 创建工作 创建一个…

leetcode:2469. 温度转换(python3解法,数学相关算法题)

难度&#xff1a;简单 给你一个四舍五入到两位小数的非负浮点数 celsius 来表示温度&#xff0c;以 摄氏度&#xff08;Celsius&#xff09;为单位。 你需要将摄氏度转换为 开氏度&#xff08;Kelvin&#xff09;和 华氏度&#xff08;Fahrenheit&#xff09;&#xff0c;并以数…

【软件安装】Windows操作系统中安装mongodb数据库和mongo-shell工具

这篇文章&#xff0c;主要介绍Windows操作系统中如何安装mongodb数据库和mongo-shell工具。 目录 一、安装mongodb数据库 1.1、下载mongodb安装包 1.2、添加配置文件 1.3、编写启动脚本&#xff08;可选&#xff09; 1.4、启动服务 二、安装mongo-shell工具 2.1、下载mo…