Linux异步IO实现方案总结

2023-11-04

一、glibc aio

1、名称

由于是glibc提供的aio函数库,所以称为glibc aio

glibc是GNU发布的libc库,即c运行库。

另外网上还有其他叫法posix aio,都是指glibc提供的这套aio实现方案。

2、主要接口

glibc aio主要包含如下接口:

函数 功能
int aio_read(struct aiocb *aiocbp); 提交一个异步读
int aio_write(struct aiocb *aiocbp); 提交一个异步写
int aio_cancel(int fildes, struct aiocb *aiocbp); 取消一个异步请求(或基于一个fd的所有异步请求,aiocbp==NULL)
int aio_error(const struct aiocb *aiocbp); 查看一个异步请求的状态(进行中EINPROGRESS?还是已经结束或出错?)
ssize_t aio_return(struct aiocb *aiocbp); 查看一个异步请求的返回值(跟同步读写定义的一样)
int aio_suspend(const struct aiocb * const list[], int nent, const struct timespec *timeout); 阻塞等待请求完成

glibc aio提供函数API,是比较通俗易懂的。

3、实现原理

在glibc aio的实现原理是,用多线程同步来模拟异步IO。实际上,为了避免线程的频繁创建、销毁,当有多个请求时,glibc aio会使用线程池,但以上原理是不会变的,尤其要注意的是:我们的回调函数是在一个单独线程中执行的。

缺点: glibc aio 广受非议,存在一些难以忍受的缺陷和bug,饱受诟病,是极不推荐使用的。详见:http://davmac.org/davpage/linux/async-io.html

二、libaio

1、名称

libaio是由linux内核提供的aio实现方案,类似于windows api。

由于是linux kernel提供的api,故也叫linux kernel aio,或者原生aio
native aio

由于linux下aio实现方式较多,网上叫法很乱,所以这里特意总结下,方便大家区分。

2、主要接口

它主要包含如下系统调用接口:

函数 功能
int io_setup(int maxevents, io_context_t *ctxp); 创建一个异步IO上下文(io_context_t是一个句柄)
int io_destroy(io_context_t ctx); 销毁一个异步IO上下文(如果有正在进行的异步IO,取消并等待它们完成)
long io_submit(aio_context_t ctx_id, long nr, struct iocb **iocbpp); 提交异步IO请求
long io_cancel(aio_context_t ctx_id, struct iocb *iocb, struct io_event *result); 取消一个异步IO请求
long io_getevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout) 等待并获取异步IO请求的事件(也就是异步请求的处理结果)

其中,struct iocb主要包含以下字段:

struct iocb {
    void     *data;  /* Return in the io completion event */
    unsigned key;   /*r use in identifying io requests */
    short           aio_lio_opcode;
    short           aio_reqprio;
    int             aio_fildes;
    union {
            struct io_iocb_common           c;
            struct io_iocb_vector           v;
            struct io_iocb_poll             poll;
            struct io_iocb_sockaddr saddr;
    } u;
};

struct io_iocb_common {
    void            *buf;
    unsigned long   nbytes;
    long long       offset;
    unsigned        flags;
    unsigned        resfd;
};

iocb是提交IO任务时用到的,可以完整地描述一个IO请求:

  • data是留给用来自定义的指针:可以设置为IO完成后的callback函数;
  • aio_lio_opcode表示操作的类型:IO_CMD_PWRITE | IO_CMD_PREAD;
  • aio_fildes是要操作的文件:fd;
  • io_iocb_common中的buf, nbytes, offset分别记录的IO请求的mem buffer,大小和偏移。
struct io_event {
    void *data;
    struct iocb *obj;
    unsigned long res;
    unsigned long res2;
};

io_event是用来描述返回结果的:

  • obj就是之前提交IO任务时的iocb;
  • res和res2来表示IO任务完成的状态。

3、实现原理

libaio与Glibc的多线程模拟不同 ,它是真正做到内核的异步通知,是真正意义上的异步IO。

听起来Kernel Native AIO几乎提供了近乎完美的异步方式,但如果你对它抱有太高期望的话,你会再一次感到失望。

使用限制: 目前libaio仅支持O_DIRECT标志,即仅支持Direct I/O。

Direct I/O可以简单理解为直接读写IO,读写期间无缓存。

Linux中直接I/O机制介绍:
https://www.ibm.com/developerworks/cn/linux/l-cn-directio/index.html

缺点: 目前libaio仅支持Direct I/O方式来对磁盘读写,这意味着,你无法利用系统的缓存,同时它要求读写的的大小和偏移要以区块的方式对齐。

三、libeio

在当年,linux下已有的AIO (异步IO)解决方案:

  • Glibc的AIO,在用户态,多线程同步来模拟的异步IO;
  • libaio,需要linux内核2.6.22以上,且仅支持Direct I/O。

但两者都存在让使用者望而却步的问题:

  • Glibc的AIO bug太多,而且IO发起者并不是最后的IO终结者(callbak是在单独的线程执行的);
  • libaio只支持O_DIRECT方式,无法利用Page cache。

正是由于上述原因,Marc Alexander Lehmann大佬决定自己开发一个AIO库,即libeio

libeio也是在用户态用多线程同步来模拟异步IO,但实现更高效,代码也更可靠,目前虽然是beta版,但已经可以上生产了(node.js底层就是用libev和libeio来驱动的)。

还要强调点:libeio里IO的终结者正是当初IO的发起者(这一点非常重要,因为IO都是由用户的request而发起,而IO完成后返回给用户的response也能在处理request的线程中完成)。

libeio提供全套异步文件操作的接口,让使用者能写出完全非阻塞的程序。

缺点: 严格来讲,libeio也不属于真正的异步IO,仍然是通过用户态多线程来模拟的,性能上与真正的异步IO有差距。

github地址:https://github.com/kindy/libeio

代码量不大,几千行,感兴趣可以研究下。

四、io_uring

在过去的数年间,针对上述缺陷,限制的很多改进努力都未果,如Glibc AIO、libaio、libeio。

虽然在使用和性能上提升了很多,但是,在Linux 上,依然没有比较完美的异步文件IO方案。

直到,Linux 5.1合入了一个新的异步IO框架和实现:io_uring,由block IO大神Jens Axboe开发。

这对当前异步IO领域无疑是一个喜大普奔的消息,这意味着,libaio的时代即将成为过去,io_uring的时代即将开启。

为了方便使用,Jens Axboe还开发了一套liburing库,同时在fio中提供了ioengine=io_uring的支持。通过liburing库,应用不必了解诸多io_uring的细节就可以简单地使用起来。例如,无需担心memory barrier,或者是ring buffer管理之类等。

一句话总结 io_uring 就是:一套全新的 syscall,一套全新的 async API,更高的性能,更好的兼容性,来迎接高 IOPS,高吞吐量的未来。

这个特性,才出来,需要5.1以上内核才能支持,具体好不好用,后续才知道,现在似乎搜索到的内容较少。

io_uring使用参考:

《原生的 Linux 异步文件操作,io_uring 尝鲜体验》

《Linux 5.1内核AIO 的新归宿:io_uring》

五、总结

linux异步IO实际上是利用了CPU和IO设备可以异步工作的特性(IO请求提交的过程主要还是在调用者线程上同步完成的,请求提交后由于CPU与IO设备可以并行工作,所以调用流程可以返回,调用者可以继续做其他事情)。

linux的异步IO发展之路,还是比较曲折的,没有一个完美的实现。不像windows下异步IO,IOCP就是标杆,各种吊打。

在目前情况下,libeio就是比较不错的方案了。

但是如果你的程序中只用到Direct I/O,那么推荐使用libaio。

在将来,随着Linux 5.1以上版本的更新,如果io_uring给力的话,linux异步IO很可能就一统天下了。

参考链接:

《linux AIO (异步IO) 那点事儿》

《异步I/O – posix aio 从入门到放弃的吐血实践》

《linux异步IO编程实例分析》

《linux异步IO的两种方式》



若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!

同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux异步IO实现方案总结 的相关文章

  • Nginx:配置worker进程的所属用户

    Nginx的配置文件 etc nginx nginx conf中定义了启动worker时的所属用户 全局块 user www data worker进程的所属用户 nginx默认设置为www data 但如果该用户配置的不正确 可能造成业务
  • Linux内核模块管理

    模块的全称是动态可加载内核模块 它是具有独立功能的程序 可以被单独编译 但不能独立运行 模块是为内核或其他模块提供功能的代码集合 这些模块可以是 Linux 源码中自带的 也可以是由硬件厂商开发的 可以想象成驱动 安装模块一般有两种方法 第
  • linux fdisk的分区和格式化和挂载相关操作说明

    注意 分区的时候要umount磁盘之后才能分区 在Ubuntu用fdisk分析需要root用户权限 第一步 先把设备卸载掉 解除占用 caizd ubuntu home share lsblk 查看大小空间 caizd ubuntu hom
  • Shell编程总结

    Shell编程总结 1 变量被定义时为空 即参加算术运算时可以直接与数值相加 被看做初值为0 2 使用变量时 需要在变量前加 即 a 3 中括号相当于test 在if语句中 if test f 1 与 if f 1 作用相同 但是需要注意中
  • Linux清除原有ssh密钥方法

    Linux清除原有ssh密钥方法 1 问题现象 以前在mac的终端下面使用ssh user localhost输入密码就可以连接到远程的SSH服务器 今天连接的时候老是提示如下错误 KENFORFORLIN kenforstar sudo
  • openEuler 20.03 LTS SP2以及SP3安装完gnome后,gdm登陆进入不了桌面问题

    一 问题原因 是由于CVE 2020 17489相关补丁引入的 暂不清楚是何原因造成 但除去该相关补丁之后 该问题消失 在网上查了下 CVE 2020 17489的问题是gnome shell的某些配置中会发现 注销账户时 登陆对话框中的密
  • Googletest 实现简要分析

    借助于 Googletest 测试框架 我们只需编写测试用例代码 并定义简单的 main 函数 编译之后并运行即可以把我们的测试用例跑起来 更详细的内容可参考 Googletest 入门 但 main 函数调用 RUN ALL TESTS
  • Ubuntu搭建Qt环境

    1 ubuntu搭建qt环境的好处 ubuntu上可以安装qtcrater 然后一键下载到板子上 不需要手动编译 2 安装linux版本的qtcreater 注意 必须要先安装g 再安装qtcreater 否则会出问题 下载g 编译器 su
  • Linux异步IO实现方案总结

    一 glibc aio 1 名称 由于是glibc提供的aio函数库 所以称为glibc aio glibc是GNU发布的libc库 即c运行库 另外网上还有其他叫法posix aio 都是指glibc提供的这套aio实现方案 2 主要接口
  • u-boot常用命令

    u boot常用命令 查看u boot所支持的命令 查询命令 u boot版本 环境变量 板子相关信息 环境变量操作 内存操作 网络操作 EMMC和 SD卡操作 FAT 格式文件系统操作 EXT格式文件系统操作 ubi格式文件系统操作 bo
  • 网络编程之三

    代码1 chat tcp client1 c include header h int main int argc char argv int connfd 1 if 0 gt connfd socket AF INET SOCK STRE
  • Ubuntu搭建Nginx服务器

    Ubuntu搭建Nginx服务器 安装Nginx 配置文件 全局配置文件 子配置文件管理 sites availables和sites enabled default配置文件 启动 停止 重启Nginx 启动 停止 重启 查询 其他设置 自
  • Linux的c编程-文件节点的打开与读写操作

    1 open 打开文件 相关函数 read write fcntl close link stat umask unlink fopen 表头文件 include
  • /sys/module 模块信息与 /proc/modules

    看到一篇关于 proc moduels 以及 sys module 相关介绍 转载一下 http linux chinaunix net techdoc system 2008 07 18 1018163 shtml 在编译模块的时候 如果
  • Shell:查看进程与对应的线程

    1 通过 ps efL grep 进程ID或名字 UID PID PPID LWP C NLWP STIME TTY TIME CMD user 228298 201990 228298 0 2 00 14 pts 0 00 00 00 t
  • Linux中普通用户和ROOT用户对Java JDK的配置

    Linux中对对各种工具文件不需要想Windows中似的 还要先一步一步的安装 有的还需要配置环境变量 比如Windows对Java的安装过程 在Linux中 使用指令 tar zxvf 文件名 注意空格 解压完 tar gz 文件 或使用
  • Linux学习笔记(九) -- 利用Code::Blocks建立C++静态链接库

    1 测试平台 测试平台 Linux版本 Ubuntu 18 04 LTS Code Blocks版本 16 01 2 操作步骤 2 1 启动Code Blocks 2 2 新建静态链接库工程 1 选择 File 菜单中的 New Proje
  • Ubuntu(20.04):设置DNS

    编辑文件 etc systemd resolved conf 设置DNS 8 8 8 8 114 114 114 114 保存退出后 以sudo身份运行 systemctl restart systemd resolved systemct
  • Ubuntu下安装和注册beyond compare 4

    下载 安装 下载安装包网址 Ubuntu上选择Debian安装包 https www scootersoftware com download php sudo dpkg i bcompare 4 4 6 27483 amd64 deb 注
  • 通过进入单用户模式解决linux中的rc.local修改后无法启动的问题

    问题 本想将teamviewer这个软件随linux自启动 所以将其启动命令放在rc local中 但是重启后发现linux启动不起来了 系统前面都是正常启动的 就是无法进入帐户登陆界面 无法输入root帐号密码 不能登陆到系统 按了ctr

随机推荐

  • ubuntu安装配置Nginx

    Nginx下载 Nginx官网下载页面 下载其中的Stable version 我这里是nginx 1 20 1 安装依赖库 sudo apt install libpcre3 libpcre3 dev zlib1g dev openssl
  • Java HashMap什么时候进行扩容呢?

    下文笔者讲述HashMap什么时间进行扩容的简介说明 如下所示 HashMap进行扩容的时间点 1 put元素时 会触发resize方法在内部进行扩容 将把原来的数据rehash放进扩容后的桶中 2 数组的容量必须达到树化的容量的最小值默认
  • python如何输出矩阵的行数与列数?

    Python如何输出矩阵的行数与列数 对于pyhton里面所导入或者定义的矩阵或者表格数据 想要获得矩阵的行数和列数有以下方法 1 利用shape函数输出矩阵的行和列 x shape函数可以输出一个元组 m n 其中元组的第一个数m表示矩阵
  • 解决口袋动画产生的片头动画无法使用powerpoint导出成视频的问题

    问题 口袋动画中的片头做得非常漂亮 放在ppt中可以显示 但是一旦使用ppt中的导出功能就会闪退 如何解决 解决 1 点击 口袋动画PA SHEET 2 动画盒子 gt 选择 3 下载 4 导出
  • linux查看inode使用情况,Linux Inode信息及inode使用率是指什么? - 新手站长网

    Linux服务器云监控会显示Inode信息及inode使用率选项 很多用户什么原因 新手站长网分享Linux系统下的inode原理 inode使用率及inode查询命令 什么是inode信息 Linux inode信息 什么是inode信息
  • 无线充电接收原理图—TWS充电盒方案

    无线充电接收原理图 TWS充电盒方案 原理图百度云下载 链接 https pan baidu com s 1VuIYg5vgPX6wKrWYCZ0bmg 提取码 iq3w
  • java-引用与对象

    我们先定义一个简单的类 class Vehicle int passengers int fuelcap int mpg 有了这个模板 就可以用它来创建对象 Vehicle veh1 new Vehicle 通常把这条语句的动作称之为创建一
  • 目前主流的几款文件上传控件,以及优缺点

    1 WebUploader 官网 http fex baidu com webuploader getting started html API http fex baidu com webuploader doc index html W
  • Linux 帮助手册安装不全

    今天在新安装的 fedora 17 虚拟机上写多线程程序的时候 本想查看下系统帮助手册中关于线程相关函数的说明 结果 tom localhost thread man pthread create No manual entry for p
  • 手把手教你配置BSC(币安智能链)网络,只需5分钟

    这里就用小狐狸 Metamask 钱包了 因为本人坚信用狐狸钱包日后可以撸到空投 1 PC端Chrome浏览器安装metamask钱包插件 要去Metamask官网下载钱包哦 然后把插件添加至Chrome浏览器扩展程序中 这个不会的小伙伴欢
  • 【Vue系列5】——Vue组件化开发入门篇

    点赞多大胆 就有多大产 开源促使进步 献给每一位技术使用者和爱好者 干货满满 摆好姿势 点赞发车 前言 本文主要说一下组件化开发一些概念和基本使用 有基础的小伙伴应该听过组件通信 插槽等这样的概念 我们下篇再说 在具体编码之前我们需要知道两
  • JS判断数组是否存在交集

    2019独角兽企业重金招聘Python工程师标准 gt gt gt
  • 服务器卡死,重启报错: INFO: task blocked for more than 120 seconds

    问题 服务器负载很高 但是CPU利用率不高 服务器经常夯住 网站打不开 SSH连接非常不稳定 输入命令夯住 重启服务器报错 INFO task blocked for more than 120 seconds 问题原因 默认情况下 Lin
  • Linux下安装配置tomcat

    Linux下安装配置tomcat 1 安装 Tomcat版本 6 0 29 Linux版本 Radhat Enterprise 5 5 Jdk版本 1 6 0 20 解压缩tomcat tar zxvf apache tomcat 6 0
  • python+django网上美食菜品订餐系统的设计与实现vue

    随着科学技术的飞速发展 社会的方方面面 各行各业都在努力与现代的先进技术接轨 通过科技手段来提高自身的优势 好吃网线上订餐系统当然也不能排除在外 从美食类型 美食信息的统计和分析 在过程中会产生大量的 各种各样的数据 本文以好吃网线上订餐系
  • JS - 基本语法

    JavaScript是一种脚本语言 主要功能是 动态修改html页面内容 包括创建 删除html页面元素 修改html页面元素的内容 外观 位置 大小等 数据类型和变量 任何语言都离不开数据类型和变量 虽然JavaScript语言是弱类型的
  • D-S证据理论

    一 前言 20世纪60年代美国哈佛大学数学家A P Dempster利用上 下限概率来解决多值映射问题方面的研究工作 自1967年起连续发表了一系列论文 标志着证据理论的诞生 Dempster的学生G Shafer对证据理论做了进一步发展
  • js中for循环与定时器

    js中for循环和定时器的问题 有四个解决方法 这里面涉及到了同步与异步的问题 也可以理解为 解决方法1 闭包 解决方法2 拆分结构 解决方法3 let let和var区别 解决方法4 第三个参数 for var i 0 i lt 6 i
  • 超酷的13个CSS有趣学习网站

    13个CSS有趣学习网站 今天来给大家推荐13个辅助你学习巩固知识的网站 让你边玩边学边记 因为这些网站大多都是国外的大佬们做的 所以网页大多都是英文 为了更好地使用 给你们推荐两个翻译的方式 使用Chrome浏览器自带的翻译功能 可以中英
  • Linux异步IO实现方案总结

    一 glibc aio 1 名称 由于是glibc提供的aio函数库 所以称为glibc aio glibc是GNU发布的libc库 即c运行库 另外网上还有其他叫法posix aio 都是指glibc提供的这套aio实现方案 2 主要接口