Linux I/O编程:I/O多路复用与异步 I/O对比

news2024/11/14 7:06:05

文章目录

    • 0. 引言
    • 1. I/O 模型简介
      • 1.1 阻塞 I/O(Blocking I/O)
      • 1.2 非阻塞 I/O(Non-Blocking I/O)
      • 1.3 信号驱动式 I/O(Signal-Driven I/O)
      • 1.4 多路复用 I/O(I/O Multiplexing)
      • 1.5 异步 I/O(Asynchronous I/O)
    • 2. 多路复用 I/O VS 异步 I/O 分析
      • 2.1 多路复用 I/O
      • 2.2 异步 I/O
      • 2.3 多路复用 I/O 与异步 I/O 的比较
      • 2.4 总结
    • 3. 多路复用 I/O 和异步 I/O示例代码
      • 3.1 多路复用 I/O 示例(`select`)
      • 3.2 异步 I/O 示例(`aio_read`)
      • 3.3 代码说明
    • 4. 参考文档

0. 引言

本文将简要介绍 Linux 中的多路复用 I/O 和异步 I/O 模型,并编写示例代码简述。对于网络 I/O,特别是 UDP 和 TCP,多路复用 I/O(如 selectepoll())通常是更好的选择。而异步 I/O(如 libaio)只建议用在文件和块设备的 I/O 操作。

1. I/O 模型简介

Linux 提供了五种常见的 I/O 模型:阻塞 I/O、非阻塞 I/O、多路复用 I/O、信号驱动 I/O 和异步 I/O。

1.1 阻塞 I/O(Blocking I/O)

阻塞 I/O 是最简单的模型,进程会在 I/O 操作完成之前被挂起。适用于低并发、对性能要求不高的场景。

工作原理

  • 进程发起 I/O 操作,若数据不可用,进程会被阻塞,直到数据准备好。

1.2 非阻塞 I/O(Non-Blocking I/O)

非阻塞 I/O 允许进程继续执行其他任务,当数据不可用时,系统返回一个错误码(如 EAGAIN)。进程可以选择继续做其他事情,或者再次尝试 I/O 操作。

工作原理

  • 进程发起 I/O 操作后,如果数据不可用,系统返回错误码,进程继续执行其他任务。

1.3 信号驱动式 I/O(Signal-Driven I/O)

通过内核向进程发送信号通知数据准备情况,进程可以继续执行其他任务,直到收到信号时再处理数据。

适用场景:不希望主动轮询的应用,通常用于低延迟要求的系统或设备驱动

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

多路复用 I/O 允许一个进程同时监控多个 I/O 通道,避免因等待 I/O 完成而导致的阻塞。

工作原理

  • 通过 select()poll()epoll() 等系统调用,进程可以同时监控多个 I/O 通道,当某个通道就绪时,进程会被通知。
应用进程 内核 select 系统调用,阻塞 数据未准备 等待数据 数据准备好 返回可读条件 read 系统调用 成功响应 应用进程 内核

1.5 异步 I/O(Asynchronous I/O)

异步 I/O 的核心思想是,进程发起 I/O 操作后,系统立即返回,I/O 操作在后台完成。当操作完成时,系统会通知进程。

工作原理

  • 进程发起异步 I/O 操作,系统立即返回,I/O 在后台进行,完成时通知进程。
应用进程 内核 aio_read 返回 数据未准备 等待数据 数据准备好 通知操作完成 处理数据 应用进程 内核

2. 多路复用 I/O VS 异步 I/O 分析

2.1 多路复用 I/O

工作原理

多路复用 I/O 允许一个进程同时监控多个 I/O 通道。在 Linux 中,常用的系统调用包括 select()poll()epoll()

  • select():适合少量文件描述符,效率较低。
  • poll():与 select() 类似,但支持更多文件描述符。
  • epoll():高效地处理大量并发连接,采用事件驱动机制。

优劣势

多路复用允许单个进程处理多个 I/O 操作,减少线程切换的开销。然而,随着文件描述符数量的增加,轮询的开销也会增加。epoll() 通过事件驱动的方式,在大规模并发场景中表现优异。

2.2 异步 I/O

工作原理

异步 I/O 的关键是,进程发起 I/O 操作后,系统立即返回,后台继续执行 I/O 操作,而进程可以继续执行其他任务。当 I/O 操作完成时,系统通过回调函数、信号或其他机制通知进程。

Linux 中的异步 I/O 接口有两种主要实现方式:

  • POSIX AIO:通过 aio_readaio_write 提交异步 I/O 操作,操作完成后,进程可以通过 aio_erroraio_return 获取结果。需要注意的是,POSIX AIO 在某些 Linux 发行版中可能是基于用户空间的模拟,而不是真正的异步 I/O,这可能会影响其性能。
  • libaio:高效的异步 I/O 接口,直接与内核交互,减少线程上下文切换。libaio 特别适合磁盘和文件系统的异步块读写操作。

带来的挑战

  • 资源管理:异步 I/O 需要额外的内存和控制块,可能导致内存泄漏或资源管理困难。
  • 线程调度:异步 I/O 可能会引入线程切换和上下文切换的开销,尤其在大量小 I/O 操作时,性能可能下降。
  • 错误处理:异步 I/O 错误处理较为复杂,特别是回调嵌套或并发操作时,状态同步问题尤为突出。

2.3 多路复用 I/O 与异步 I/O 的比较

  • 适用场景

    • 多路复用 I/O:适用于网络 I/O 场景,特别是 UDP 和 TCP。epoll() 在处理大量并发连接时表现优异。
    • 异步 I/O:适用于文件和块设备的 I/O 操作,如磁盘读写。libaio 在减少上下文切换和提高磁盘 I/O 性能方面效果显著。
  • 性能和复杂性

    • 多路复用 I/O:简单易用,适合大多数网络应用场景。epoll() 在高并发场景下性能优越。
    • 异步 I/O:虽然性能潜力大,但实现复杂,错误处理和资源管理较为困难。
  • UDP 无连接协议:UDP 本身是无连接协议,内核的非阻塞 I/O 和事件驱动模型已经非常高效。UDP 数据包的发送操作不涉及复杂的连接管理,使用非阻塞 I/O 或事件驱动模型(如 selectepoll)即可高效处理并发。

2.4 总结

对于网络 I/O,特别是 UDP 和 TCP,多路复用 I/O(如 selectepoll())通常是更好的选择。而异步 I/O(如 libaio)只建议用在文件和块设备的 I/O 操作。

3. 多路复用 I/O 和异步 I/O示例代码

3.1 多路复用 I/O 示例(select

这个例子演示了如何使用 select 实现多路复用 I/O,监听多个文件描述符(如标准输入和套接字)。

#include <iostream>
#include <unistd.h>
#include <sys/select.h>
#include <fcntl.h>
#include <string.h>

int main() {
    fd_set read_fds;
    struct timeval timeout;
    
    // 创建标准输入的文件描述符集
    FD_ZERO(&read_fds);
    FD_SET(STDIN_FILENO, &read_fds);

    // 设置 select 的超时,单位是秒和微秒
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;

    int ret = select(STDIN_FILENO + 1, &read_fds, NULL, NULL, &timeout);

    if (ret == -1) {
        std::cerr << "select failed!" << std::endl;
        return -1;
    } else if (ret == 0) {
        std::cout << "Timeout: No input within 5 seconds" << std::endl;
    } else {
        if (FD_ISSET(STDIN_FILENO, &read_fds)) {
            char buffer[1024];
            ssize_t len = read(STDIN_FILENO, buffer, sizeof(buffer) - 1);
            if (len > 0) {
                buffer[len] = '\0';
                std::cout << "Input: " << buffer << std::endl;
            }
        }
    }

    return 0;
}

3.2 异步 I/O 示例(aio_read

这个例子演示了如何使用异步 I/O 读取文件内容。我们将使用 aio_read 来异步地从文件中读取数据。

#include <iostream>
#include <fstream>
#include <aio.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <errno.h>

#define FILE_NAME "test.txt"

int main() {
    // 打开文件
    int fd = open(FILE_NAME, O_RDONLY);
    if (fd == -1) {
        std::cerr << "Failed to open file: " << strerror(errno) << std::endl;
        return -1;
    }

    // 准备异步 I/O 控制块
    struct aiocb aio;
    memset(&aio, 0, sizeof(aio));
    aio.aio_fildes = fd;
    aio.aio_buf = malloc(1024);  // 分配内存空间用于读取数据
    aio.aio_nbytes = 1024;
    aio.aio_offset = 0;

    // 提交异步读取操作
    if (aio_read(&aio) == -1) {
        std::cerr << "aio_read failed: " << strerror(errno) << std::endl;
        close(fd);
        return -1;
    }

    // 等待异步 I/O 完成
    while (aio_error(&aio) == EINPROGRESS) {
        // 在此可以执行其他任务
        std::cout << "Waiting for I/O to complete..." << std::endl;
        sleep(1);
    }

    // 获取异步 I/O 操作的状态
    int ret = aio_return(&aio);
    if (ret == -1) {
        std::cerr << "aio_return failed: " << strerror(errno) << std::endl;
        free((void*)aio.aio_buf);
        close(fd);
        return -1;
    }

    // 输出读取的内容
    std::cout << "Async read completed, data: " << (char*)aio.aio_buf << std::endl;

    // 清理资源
    free((void*)aio.aio_buf);
    close(fd);

    return 0;
}

3.3 代码说明

多路复用 I/O (select):

  1. FD_SET()FD_ZERO() 用于设置和清空文件描述符集。
  2. select() 会等待 5 秒钟,如果标准输入文件描述符准备好,可以读取数据。
  3. 如果超时或没有输入,程序会输出“Timeout”。

异步 I/O (aio_read):

  1. 使用 open() 打开一个文件并读取数据。
  2. 设置异步 I/O 控制块 aiocb,并调用 aio_read() 提交异步操作。
  3. 通过 aio_error() 检查 I/O 操作是否正在进行,直到操作完成。
  4. 一旦 I/O 完成,使用 aio_return() 获取结果,并输出异步读取的内容。

编译和运行:

g++ -o async_io async_io.cpp -lrt
./async_io

4. 参考文档

一顿饭的事儿,搞懂了Linux5种IO模型

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

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

相关文章

C++11的一些特性

1、列表初始化&#xff0c;对内置类型和自定义类型都可以使用列表进行初始化——一切都可以用列表初始化 不要和初始化列表混了 std::initializer_list临时对象作为函数的参数&#xff0c;用来接收{}括起来的的初始化列表 容器中有用initializer_list作为参数的构造函数&…

MySQL多系统安装配置教程(Windows、Ubuntu、Centos)

专题目标 • 掌握在Windows下安装MySQL数据库 • 掌握在CentOS下安装MySQL数据库 • 掌握在Ubuntu下安装MySQL数据库 一、在Windows下安装MySQL数据库 • Windows下推荐使用安装程序进行安装 • 安装程序下载地址&#xff1a;https://dev.mysql.com/downloads/ 通过上面的安装…

关于 npm 更新镜像源问题

npm&#xff08;Node Package Manager&#xff09;&#xff0c;是一个NodeJS包管理和分发工具&#xff0c;已经成为了非官方的发布Node模块&#xff08;包&#xff09;的标准。&#xff09; 查看当前npm版本 npm -v 10.9.0 执行以下命令报错 npm install --registryhttp…

Netty篇(入门编程)

目录 一、Hello World 1. 目标 2. 服务器端 3. 客户端 4. 流程梳理 &#x1f4a1; 提示 5. 运行结果截图 二、Netty执行流程 1. 流程分析 2. 代码案例 2.1. 引入依赖 2.2. 服务端 服务端 服务端处理器 2.3. 客户端 客户端 客户端处理器 2.4. 代码截图 一、Hel…

文本语义分块、RAG 系统的分块难题:小型语言模型如何找到最佳断点

文本语义分块、RAG 系统的分块难题&#xff1a;小型语言模型如何找到最佳断点&#xff1f; 转自jina最新的关于文本语义分块的分享和模型 之前我们聊过RAG 里文档分块 (Chunking) 的挑战&#xff0c;也介绍了 迟分 (Late Chunking) 的概念&#xff0c;它可以在向量化的时候减…

大数据技术在金融风控中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 大数据技术在金融风控中的应用 大数据技术在金融风控中的应用 大数据技术在金融风控中的应用 引言 大数据技术概述 定义与原理 发…

小程序中引入下载到本地的iconfont字体图标加载不出来问题解决

我这个是uniapp项目,字体图标都是一样的,在vue项目中web端、uniapp运行到h5都没问题,但是运行到小程序加载不出来,报错如下: 不让用本地路径,所以我们要转为base64编码,这里给大家提供一个工具,它可以把本地字体文件转为base64:transfonter 进入官网后,第一步: …

MYSQL隔离性原理——MVCC

表的隐藏字段 表的列包含用户自定义的列和由系统自动创建的隐藏字段。我们介绍3个隐藏字段&#xff0c;不理解也没有关系&#xff0c;理解后面的undo log就懂了&#xff1a; DB_TRX_ID &#xff1a;6 byte&#xff0c;最近修改( 修改/插入 )事务ID&#xff0c;记录创建这条记…

vue3 + element-plus 的 upload + axios + django 文件上传并保存

之前在网上搜了好多教程&#xff0c;一直没有找到合适自己的&#xff0c;要么只有前端部分没有后端&#xff0c;要么就是写的不是很明白。所以还得靠自己摸索出来后&#xff0c;来此记录一下整个过程。 其实就是不要用默认的 action&#xff0c;要手动实现上传方式 http-reque…

【C++课程学习】:二叉搜索树

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;C课程学习 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 二叉树搜索树的概念&#xff1a; 节点的结构&#xff1a; ⚽️结构&#xff1a; ⚽️ 构造函数&…

Axure是什么软件?全方位解读助力设计入门

在产品设计和开发领域&#xff0c;Axure是一款大名鼎鼎且功能强大的软件&#xff0c;它为专业人士和团队提供了卓越的设计支持&#xff0c;帮助他们将创意转化为实际可操作的产品原型。 一、Axure 的基本介绍 Axure是一款专业的原型设计工具&#xff0c;主要用于创建交互式的…

java里面使用groovy案例+详解

场景&#xff1a; 最近有一个计算商品运费的&#xff0c;如果商品的数量大于快递公司设置的数量 10 那么超出部分也需要计算额外运费&#xff0c;那么这些计算过程代码我能不能不在java里面写呢&#xff0c;用一种可配置化的方式来根据不同的传参计算出运费&#xff1f; 页面传…

单体架构 IM 系统之核心业务功能实现

在上一篇技术短文&#xff08;单体架构的 IM 系统设计&#xff09;中&#xff0c;我们讨论了在 “用户规模小、开发人员少、开发时间短” 的业务背景下&#xff0c;采取 “怎么简单怎么做&#xff0c;怎么快怎么来” 的研发策略&#xff0c;于是设计了 单体架构的IM系统&#x…

Linux部署nginx访问文件403

问题描述&#xff1a;在linux服务器上通过nginx部署&#xff0c;访问文件403 新配置了一个用户来部署服务&#xff0c;将部署文件更新到原有目录下&#xff0c;结果nginx访问403 原因&#xff1a;没有配置文件的读写权限&#xff0c;默认不可读写&#xff0c;nginx无法访问到文…

解决 C/C++ 中 “invalid use of incomplete type” 编译错误

解决 C/C++ 中 “invalid use of incomplete type” 编译错误 一、错误原因二、常见场景三、解决方法四、最佳实践五、总结在 C 和 C++ 编程中,invalid use of incomplete type 错误通常发生在尝试使用一个未完全定义的类型时。这个错误表明编译器在当前上下文中没有足够的信息…

使用 Python 实现高效网页爬虫——从获取链接到数据保存

前言 在这个时代,网络爬虫已成为数据分析与信息收集不可或缺的技术之一。本文将通过一个具体的Python项目来介绍如何构建一个简单的网络爬虫,它能够自动抓取指定网站的文章链接、标题、正文内容以及图片链接,并将这些信息保存为CSV文件。 目标网站 一、准备工作 在开始编…

C# 有趣的小程序—桌面精灵详细讲解

C# 桌面精灵详细讲解 最近写了一个简化版桌面精灵&#xff0c;效果如图所示&#xff0c;可以实现切换动画&#xff0c;说话、鼠标拖动&#xff0c;等功能。具体如何做&#xff0c;我发布了一个资源里面包含ppt详解、源代码以及动画素材。放心吧&#xff0c;免费的&#xff0c;…

微软日志丢失事件敲响安全警钟

NEWS | 事件回顾 最近&#xff0c;全球最大的软件公司之一——微软&#xff0c;遭遇了一场罕见的日志丢失危机。据报告&#xff0c;从9月2日至9月19日&#xff0c;持续长达两周的时间里&#xff0c;微软的多项核心云服务&#xff0c;包括身份验证平台Microsoft Entra、安全信息…

Mysql ERROR 1451 (23000) 外键处理异常

通过临时设置外键失效&#xff0c;来规避报错 第一步 # 临时设置外键失效 SET FOREIGN_KEY_CHECKS 0; 第二步&#xff1a;执行更新或者删除操作 第三步&#xff1a; # 操作结束后恢复外键 SET FOREIGN_KEY_CHECKS 1;

智慧社区可视化解决方案:科技引领社区服务与管理新篇章

随着社会的发展&#xff0c;智慧社区作为新型城镇化发展目标和社区服务体系建设的重要举措&#xff0c;正逐步改变着我们的生活方式。智慧社区通过综合运用现代科学技术&#xff0c;整合区域资源&#xff0c;提升社区治理和服务水平&#xff0c;为居民提供更为便捷、高效、安全…