前言

io_uring 是 Linux 内核中直接通过系统调用接口暴露的一个特性,它主要用于提高异步 I/O 操作的性能。由于 io_uring 是内核的一部分,它并不通过传统的库文件(如 .so 文件)来提供接口,而是直接通过系统调用来访问。

因此,io_uring 没有特定的“头文件”和“库文件”需要你在应用程序中直接链接。相反,你需要包含 Linux 内核提供的头文件,并在你的应用程序中直接调用相关的系统调用

头文件

为了在你的 C 或 C++ 程序中使用 io_uring,你需要包含 Linux 内核提供的头文件。这个头文件通常是 <linux/io_uring.h>,但请注意,这个头文件通常位于内核源代码树中,而不是你的系统头文件目录中。然而,大多数现代 Linux 发行版(包括 Debian)都会将这个头文件(或类似功能的头文件)的一部分作为用户空间开发接口的一部分,并提供在如 /usr/include/linux/ 或 /usr/include/x86_64-linux-gnu/asm-generic/(取决于你的架构和发行版)等位置。

但是,由于直接包含内核头文件可能会引入兼容性问题(因为内核头文件可能会随内核版本的变化而变化),因此更推荐的做法是使用库,如 liburing,它提供了对 io_uring 的封装和更稳定的接口。

使用 liburing

liburing 是一个用户空间库,它封装了 io_uring 接口,使得在应用程序中使用 io_uring 变得更加容易和安全。你可以通过包管理器(如 apt-get)安装 liburing:

sudo apt-get install liburing-dev

安装后,你可以包含 liburing 提供的头文件(如 <liburing/io_uring.h>),并在你的应用程序中链接 liburing 库(通常是通过编译器选项 -luring 来完成)。


前提

欲启用 boost::asio 对于 io_uring 的支持,这需要以下几个先决条件;

1、boost 1.78 及以上发行版本

2、Linux kernel 5.10 及以上发行版本


启用

Makefile文件添加两个宏定义-DBOOST_ASIO_HAS_IO_URING -DBOOST_ASIO_DISABLE_EPOLL

链接库: -luring


性能分析

启用以后,ASIO性能没有得到任何有效的提升,测试环境记录:Debian11推流50路,CPU100%


在Linux Kernel 5.10中,关于io_uring和Boost.Asio库的结合使用,以及它们如何影响异步I/O操作和事件多路分解(demultiplexing)机制,这里有一些详细的解释。


io_uring 和 Boost.Asio

Boost.Asio 是一个跨平台的 C++ 库,用于网络和低级 I/O 编程,包括异步操作。从某个版本开始(取决于Boost.Asio的具体版本),它开始支持使用io_uring进行文件相关的异步操作,这是通过定义BOOST_ASIO_HAS_IO_URING宏来实现的。io_uring是Linux内核中引入的一个高效I/O框架,旨在提高异步I/O操作的性能。


Demultiplexing 机制

使用 epoll:默认情况下,Boost.Asio使用epoll(对于支持epoll的Linux系统)来多路分解(demultiplex)其他类型的事件源,如网络套接字事件。epoll是一种高效的I/O事件通知机制,可以监视多个文件描述符上的事件。

使用 io_uring:如果定义了BOOST_ASIO_HAS_IO_URING,Boost.Asio将使用io_uring来处理与文件相关的异步操作。这是因为io_uring对于文件I/O特别有效,可以提供比传统方法(如io_submit)更低的延迟和更高的吞吐量。

禁用 epoll:如果除了定义BOOST_ASIO_HAS_IO_URING之外,还定义了BOOST_ASIO_DISABLE_EPOLL,那么Boost.Asio将尝试使用io_uring来处理所有类型的异步操作,而不仅仅是文件相关的操作。然而,需要注意的是,io_uring可能不是所有类型异步操作的最佳选择,特别是在处理网络I/O时。

线程

Demultiplexing 线程:无论是使用epoll还是io_uring进行事件多路分解,这些操作都是在调用io_context::run(), io_context::run_one(), io_context::poll()或io_context::poll_one()的线程之一中进行的。这意味着这些线程将负责处理所有异步操作的事件通知。

异步主机解析线程:对于异步主机名解析(如使用ip::tcp::resolver::async_resolve()或ip::udp::resolver::async_resolve()),Boost.Asio会创建一个额外的线程来模拟异步操作。这个线程是在第一次调用这些函数之一时创建的,并且用于处理DNS查询等任务。

Scatter-Gather

Scatter-Gather是一种数据传输机制,允许在单个操作中从多个不连续的内存缓冲区中读取或写入数据。在Boost.Asio和io_uring的上下文中,单个操作最多可以传输min(64, IOV_MAX)个缓冲区。这里的64是io_uring的一个限制,而IOV_MAX是系统级别的限制,表示单个I/O操作中可以包含的最大iovec数量。这意味着在实际应用中,你可能需要根据你的系统和Boost.Asio的版本调整你的代码,以确保不会超出这些限制。


源码分析

Platform-Specific Implementation Notes - 1.82.0 (boost.org)

asio io_uring backend源码分析 - 知乎 (zhihu.com)