io_uring 系统调用详解
1. 函数介绍
io_uring 是Linux 5.1引入的高性能异步I/O框架,提供了一种现代化的异步I/O接口。相比传统的AIO(异步I/O),io_uring具有更好的性能、更低的系统调用开销和更丰富的功能。它使用共享内存环形缓冲区实现用户空间和内核空间的高效通信。
2. 函数原型
#include <liburing.h>
#include <linux/io_uring.h>
// 初始化io_uring实例
int io_uring_queue_init(unsigned entries, struct io_uring *ring, unsigned flags);
// 销毁io_uring实例
int io_uring_queue_exit(struct io_uring *ring);
// 提交I/O请求
int io_uring_submit(struct io_uring *ring);
// 等待I/O完成事件
int io_uring_wait_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr);
// 标记完成事件已处理
void io_uring_cqe_seen(struct io_uring *ring, struct io_uring_cqe *cqe);
// 准备I/O操作
void io_uring_prep_read(struct io_uring_sqe *sqe, int fd, void *buf, unsigned nbytes, __u64 offset);
void io_uring_prep_write(struct io_uring_sqe *sqe, int fd, const void *buf, unsigned nbytes, __u64 offset);
void io_uring_prep_openat(struct io_uring_sqe *sqe, int dfd, const char *path, int flags, mode_t mode);
void io_uring_prep_close(struct io_uring_sqe *sqe, int fd);
void io_uring_prep_fsync(struct io_uring_sqe *sqe, int fd, unsigned fsync_flags);
3. 功能
io_uring 提供了完整的异步I/O解决方案,支持文件I/O、网络I/O、文件操作等多种操作类型。它通过共享内存环形缓冲区实现零拷贝的数据传输,显著提高了I/O性能。
4. 参数说明
io_uring_queue_init参数:
- unsigned entries: 环形缓冲区大小(必须是2的幂)
- *struct io_uring ring: io_uring实例指针
- unsigned flags: 初始化标志
io_uring_queue_exit参数:
- *struct io_uring ring: 要销毁的io_uring实例
io_uring_submit参数:
- *struct io_uring ring: io_uring实例
io_uring_wait_cqe参数:
- *struct io_uring ring: io_uring实例
- **struct io_uring_cqe cqe_ptr: 完成事件指针
5. 返回值
- 成功: 返回非负值或0
- 失败: 返回负的错误码
6. 相似函数,或关联函数
- io_setup/io_destroy: 传统的AIO接口
- io_submit/io_cancel: 传统的AIO提交和取消
- io_getevents: 传统的AIO事件获取
- aio_read/aio_write: POSIX AIO接口
- epoll_wait/poll: 传统的I/O多路复用
7. 示例代码
示例1:基础io_uring使用
#include <liburing.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
/**
* 演示基础io_uring使用方法
*/
int demo_io_uring_basic() {
struct io_uring ring;
int ret;
printf("=== 基础io_uring使用示例 ===\n");
// 初始化io_uring实例
printf("1. 初始化io_uring实例:\n");
ret = io_uring_queue_init(32, &ring, 0);
if (ret < 0) {
printf(" 初始化失败: %s\n", strerror(-ret));
return -1;
}
printf(" ✓ io_uring实例初始化成功\n");
printf(" 环形缓冲区大小: 32\n");
// 显示io_uring信息
printf(" io_uring信息:\n");
printf(" 提交队列大小: %u\n", ring.sq.ring_sz);
printf(" 完成队列大小: %u\n", ring.cq.ring_sz);
printf(" 特性标志: 0x%x\n", ring.features);
// 创建测试文件
printf("\n2. 创建测试文件:\n");
const char *test_filename = "io_uring_test.txt";
int test_fd = open(test_filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (test_fd == -1) {
perror(" 创建测试文件失败");
io_uring_queue_exit(&ring);
return -1;
}
printf(" ✓ 测试文件创建成功: %s\n", test_filename);
// 准备测试数据
const char *test_data = "Hello from io_uring! This is a test message.\n";
size_t data_size = strlen(test_data);
// 使用io_uring写入数据
printf("\n3. 使用io_uring写入数据:\n");
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
if (!sqe) {
printf(" 获取SQE失败\n");
close(test_fd);
unlink(test_filename);
io_uring_queue_exit(&ring);
return -1;
}
// 准备写入操作
io_uring_prep_write(sqe, test_fd, test_data, data_size, 0);
sqe->user_data = 1; // 设置用户数据
printf(" 准备写入操作:\n");
printf(" 文件描述符: %d\n", test_fd);
printf(" 数据大小: %zu 字节\n", data_size);
printf(" 偏移量: 0\n");
// 提交操作
ret = io_uring_submit(&ring);
if (ret <= 0) {
printf(" 提交操作失败: %s\n", strerror(-ret));
close(test_fd);
unlink(test_filename);
io_uring_queue_exit(&ring);
return -1;
}
printf(" ✓ 操作提交成功,提交了 %d 个请求\n", ret);
// 等待完成
printf("\n4. 等待I/O操作完成:\n");
struct io_uring_cqe *cqe;
ret = io_uring_wait_cqe(&ring, &cqe);
if (ret < 0) {
printf(" 等待完成事件失败: %s\n", strerror(-ret));
close(test_fd);
unlink(test_filename);
io_uring_queue_exit(&ring);
return -1;
}
printf(" ✓ I/O操作完成\n");
printf(" 用户数据: %llu\n", (unsigned long long)cqe->user_data);
printf(" 结果: %d 字节\n", cqe->res);
printf(" 标志: 0x%x\n", cqe->flags);
// 标记完成事件已处理
io_uring_cqe_seen(&ring, cqe);
// 读取写入的数据验证
printf("\n5. 验证写入结果:\n");
close(test_fd);
test_fd = open(test_filename, O_RDONLY);
if (test_fd != -1) {
char read_buffer[256];
ssize_t bytes_read = read(test_fd, read_buffer, sizeof(read_buffer) - 1);
if (bytes_read > 0) {
read_buffer[bytes_read] = '\0';
printf(" 读取到的数据 (%zd 字节):\n", bytes_read);
printf(" %s", read_buffer);
}
close(test_fd);
}
// 清理资源
printf("\n6. 清理资源:\n");
unlink(test_filename);
io_uring_queue_exit(&ring);
printf(" ✓ 资源清理完成\n");
return 0;
}
int main() {
return demo_io_uring_basic();
}
示例2:批量I/O操作
#include <liburing.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
/**
* 批量I/O操作演示
*/
int demo_batch_io_operations() {
struct io_uring ring;
const int batch_size = 8;
const int file_count = 5;
int ret;
printf("=== 批量I/O操作演示 ===\n");
// 初始化io_uring
printf("1. 初始化io_uring:\n");
ret = io_uring_queue_init(64, &ring, 0);
if (ret < 0) {
printf(" 初始化失败: %s\n", strerror(-ret));
return -1;
}
printf(" ✓ io_uring初始化成功\n");
// 创建测试文件
printf("\n2. 创建测试文件:\n");
int file_fds[file_count];
char filenames[file_count][32];
for (int i = 0; i < file_count; i++) {
snprintf(filenames[i], sizeof(filenames[i]), "batch_test_%d.txt", i);
file_fds[i] = open(filenames[i], O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (file_fds[i] == -1) {
perror(" 创建文件失败");
// 清理已创建的文件
for (int j = 0; j < i; j++) {
close(file_fds[j]);
unlink(filenames[j]);
}
io_uring_queue_exit(&ring);
return -1;
}
printf(" 创建文件 %d: %s\n", i, filenames[i]);
}
// 准备批量写入操作
printf("\n3. 准备批量写入操作:\n");
char *test_data[file_count];
int submitted_ops = 0;
for (int i = 0; i < file_count; i++) {
// 分配测试数据
test_data[i] = malloc(256);
if (!test_data[i]) {
perror(" 分配测试数据失败");
// 清理资源
for (int j = 0; j <= i; j++) {
if (test_data[j]) free(test_data[j]);
if (j < file_count) {
close(file_fds[j]);
unlink(filenames[j]);
}
}
io_uring_queue_exit(&ring);
return -1;
}
snprintf(test_data[i], 256,
"Batch write test data for file %d. Operation count: %d\n", i, i + 1);
// 准备多个写入操作
for (int j = 0; j < batch_size && submitted_ops < 32; j++) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
if (!sqe) {
printf(" 获取SQE失败\n");
break;
}
// 准备写入操作
io_uring_prep_write(sqe, file_fds[i], test_data[i], strlen(test_data[i]),
j * 256);
sqe->user_data = (i * batch_size + j); // 唯一标识符
submitted_ops++;
}
printf(" 为文件 %d 准备了 %d 个写入操作\n", i, batch_size);
}
printf("\n4. 批量提交I/O操作:\n");
printf(" 总共准备了 %d 个I/O操作\n", submitted_ops);
ret = io_uring_submit(&ring);
if (ret <= 0) {
printf(" 提交操作失败: %s\n", strerror(-ret));
} else {
printf(" ✓ 成功提交 %d 个I/O操作\n", ret);
}
// 等待所有操作完成
printf("\n5. 等待所有操作完成:\n");
int completed_ops = 0;
while (completed_ops < submitted_ops) {
struct io_uring_cqe *cqe;
ret = io_uring_wait_cqe(&ring, &cqe);
if (ret < 0) {
printf(" 等待完成事件失败: %s\n", strerror(-ret));
break;
}
completed_ops++;
printf(" 操作 %d 完成: 写入 %d 字节\n",
(int)cqe->user_data, cqe->res);
// 标记完成事件已处理
io_uring_cqe_seen(&ring, cqe);
}
printf(" 总共完成了 %d 个I/O操作\n", completed_ops);
// 验证写入结果
printf("\n6. 验证写入结果:\n");
for (int i = 0; i < file_count; i++) {
close(file_fds[i]);
// 重新打开文件读取
int read_fd = open(filenames[i], O_RDONLY);
if (read_fd != -1) {
struct stat st;
if (fstat(read_fd, &st) == 0) {
printf(" 文件 %s: 大小 %ld 字节\n", filenames[i], st.st_size);
}
close(read_fd);
}
}
// 清理资源
printf("\n7. 清理资源:\n");
for (int i = 0; i < file_count; i++) {
free(test_data[i]);
unlink(filenames[i]);
}
io_uring_queue_exit(&ring);
printf(" ✓ 所有资源清理完成\n");
return 0;
}
int main() {
return demo_batch_io_operations();
}
示例3:文件操作演示
#include <liburing.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
/**
* 文件操作结构
*/
typedef struct {
int fd;
char filename[64];
off_t file_size;
int operation_type; // 0:read, 1:write, 2:open, 3:close, 4:fsync
} file_operation_t;
/**
* 演示文件操作
*/
int demo_file_operations() {
struct io_uring ring;
int ret;
printf("=== 文件操作演示 ===\n");
// 初始化io_uring
printf("1. 初始化io_uring:\n");
ret = io_uring_queue_init(16, &ring, 0);
if (ret < 0) {
printf(" 初始化失败: %s\n", strerror(-ret));
return -1;
}
printf(" ✓ io_uring初始化成功\n");
// 演示异步文件打开
printf("\n2. 异步文件打开操作:\n");
const char *test_filename = "async_file_test.txt";
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
if (!sqe) {
printf(" 获取SQE失败\n");
io_uring_queue_exit(&ring);
return -1;
}
// 准备打开文件操作
io_uring_prep_openat(sqe, AT_FDCWD, test_filename,
O_CREAT | O_RDWR | O_TRUNC, 0644);
sqe->user_data = 1;
printf(" 准备打开文件: %s\n", test_filename);
ret = io_uring_submit(&ring);
if (ret <= 0) {
printf(" 提交打开操作失败: %s\n", strerror(-ret));
io_uring_queue_exit(&ring);
return -1;
}
// 等待打开完成
struct io_uring_cqe *cqe;
ret = io_uring_wait_cqe(&ring, &cqe);
if (ret < 0) {
printf(" 等待打开完成失败: %s\n", strerror(-ret));
io_uring_queue_exit(&ring);
return -1;
}
int file_fd = cqe->res;
printf(" ✓ 文件打开成功,文件描述符: %d\n", file_fd);
io_uring_cqe_seen(&ring, cqe);
// 演示异步写入操作
printf("\n3. 异步写入操作:\n");
const char *write_data = "This is asynchronous write test data.\nMultiple lines of test content.\nEnd of test data.\n";
size_t write_size = strlen(write_data);
sqe = io_uring_get_sqe(&ring);
if (!sqe) {
printf(" 获取SQE失败\n");
close(file_fd);
unlink(test_filename);
io_uring_queue_exit(&ring);
return -1;
}
io_uring_prep_write(sqe, file_fd, write_data, write_size, 0);
sqe->user_data = 2;
printf(" 准备写入数据: %zu 字节\n", write_size);
ret = io_uring_submit(&ring);
if (ret <= 0) {
printf(" 提交写入操作失败: %s\n", strerror(-ret));
} else {
printf(" ✓ 写入操作提交成功\n");
}
// 等待写入完成
ret = io_uring_wait_cqe(&ring, &cqe);
if (ret < 0) {
printf(" 等待写入完成失败: %s\n", strerror(-ret));
} else {
printf(" ✓ 写入完成: %d 字节\n", cqe->res);
io_uring_cqe_seen(&ring, cqe);
}
// 演示异步fsync操作
printf("\n4. 异步fsync操作:\n");
sqe = io_uring_get_sqe(&ring);
if (sqe) {
io_uring_prep_fsync(sqe, file_fd, 0);
sqe->user_data = 3;
printf(" 准备fsync操作\n");
ret = io_uring_submit(&ring);
if (ret > 0) {
ret = io_uring_wait_cqe(&ring, &cqe);
if (ret == 0) {
printf(" ✓ fsync完成\n");
io_uring_cqe_seen(&ring, cqe);
}
}
}
// 演示异步读取操作
printf("\n5. 异步读取操作:\n");
char read_buffer[256];
sqe = io_uring_get_sqe(&ring);
if (sqe) {
io_uring_prep_read(sqe, file_fd, read_buffer, sizeof(read_buffer) - 1, 0);
sqe->user_data = 4;
printf(" 准备读取操作\n");
ret = io_uring_submit(&ring);
if (ret > 0) {
ret = io_uring_wait_cqe(&ring, &cqe);
if (ret == 0) {
if (cqe->res > 0) {
read_buffer[cqe->res] = '\0';
printf(" ✓ 读取完成: %d 字节\n", cqe->res);
printf(" 读取内容:\n%s", read_buffer);
} else {
printf(" 读取失败或文件为空\n");
}
io_uring_cqe_seen(&ring, cqe);
}
}
}
// 演示异步关闭操作
printf("\n6. 异步关闭操作:\n");
sqe = io_uring_get_sqe(&ring);
if (sqe) {
io_uring_prep_close(sqe, file_fd);
sqe->user_data = 5;
printf(" 准备关闭文件\n");
ret = io_uring_submit(&ring);
if (ret > 0) {
ret = io_uring_wait_cqe(&ring, &cqe);
if (ret == 0) {
printf(" ✓ 文件关闭完成\n");
io_uring_cqe_seen(&ring, cqe);
}
}
}
// 清理资源
printf("\n7. 清理资源:\n");
unlink(test_filename);
io_uring_queue_exit(&ring);
printf(" ✓ 资源清理完成\n");
return 0;
}
int main() {
return demo_file_operations();
}
示例4:网络I/O演示
#include <liburing.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/**
* 演示网络I/O操作
*/
int demo_network_io() {
struct io_uring ring;
int ret;
printf("=== 网络I/O操作演示 ===\n");
// 初始化io_uring
printf("1. 初始化io_uring:\n");
ret = io_uring_queue_init(32, &ring, 0);
if (ret < 0) {
printf(" 初始化失败: %s\n", strerror(-ret));
return -1;
}
printf(" ✓ io_uring初始化成功\n");
// 演示异步socket创建
printf("\n2. 异步socket创建:\n");
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
if (!sqe) {
printf(" 获取SQE失败\n");
io_uring_queue_exit(&ring);
return -1;
}
// 注意:io_uring的网络I/O支持需要较新的内核版本
printf(" 注意:网络I/O操作需要Linux 5.5+内核支持\n");
printf(" 在本演示中,我们将展示准备网络操作的方法\n");
// 演示网络操作准备(伪代码)
printf("\n3. 网络操作准备示例:\n");
printf(" // 创建TCP socket\n");
printf(" sqe = io_uring_get_sqe(&ring);\n");
printf(" io_uring_prep_socket(sqe, AF_INET, SOCK_STREAM, 0, 0);\n");
printf(" sqe->user_data = 1;\n");
printf("\n");
printf(" // 连接服务器\n");
printf(" struct sockaddr_in addr;\n");
printf(" memset(&addr, 0, sizeof(addr));\n");
printf(" addr.sin_family = AF_INET;\n");
printf(" addr.sin_port = htons(80);\n");
printf(" addr.sin_addr.s_addr = inet_addr(\"127.0.0.1\");\n");
printf(" io_uring_prep_connect(sqe, sockfd, &addr, sizeof(addr));\n");
printf("\n");
printf(" // 发送数据\n");
printf(" const char *data = \"GET / HTTP/1.1\\r\\n\\r\\n\";\n");
printf(" io_uring_prep_send(sqe, sockfd, data, strlen(data), 0);\n");
printf("\n");
printf(" // 接收数据\n");
printf(" char buffer[1024];\n");
printf(" io_uring_prep_recv(sqe, sockfd, buffer, sizeof(buffer), 0);\n");
// 显示网络I/O优势
printf("\n=== 网络I/O优势 ===\n");
printf("1. 高性能:\n");
printf(" ✓ 零拷贝数据传输\n");
printf(" ✓ 减少系统调用开销\n");
printf(" ✓ 提高并发处理能力\n");
printf("\n2. 低延迟:\n");
printf(" ✓ 快速事件通知\n");
printf(" ✓ 减少上下文切换\n");
printf(" ✓ 优化内存访问模式\n");
printf("\n3. 可扩展性:\n");
printf(" ✓ 支持大量并发连接\n");
printf(" ✓ 高效的事件处理\n");
printf(" ✓ 灵活的缓冲区管理\n");
// 清理资源
printf("\n4. 清理资源:\n");
io_uring_queue_exit(&ring);
printf(" ✓ io_uring资源清理完成\n");
return 0;
}
int main() {
return demo_network_io();
}
示例5:性能对比测试
#include <liburing.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
/**
* 性能测试结果结构
*/
typedef struct {
const char *test_name;
long long execution_time_us;
int operation_count;
double throughput_ops;
double average_latency_us;
} performance_result_t;
/**
* 获取当前时间(微秒)
*/
long long get_current_time_us() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000LL + tv.tv_usec;
}
/**
* 传统同步I/O性能测试
*/
int test_sync_io_performance(performance_result_t *result) {
const int operation_count = 1000;
const size_t buffer_size = 4096;
char *buffer = malloc(buffer_size);
long long start_time, end_time;
if (!buffer) {
return -1;
}
printf("执行同步I/O性能测试...\n");
// 创建测试文件
const char *filename = "sync_test.dat";
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
free(buffer);
return -1;
}
start_time = get_current_time_us();
// 执行同步写入操作
for (int i = 0; i < operation_count; i++) {
// 填充测试数据
for (size_t j = 0; j < buffer_size; j++) {
buffer[j] = 'A' + (i + j) % 26;
}
ssize_t written = write(fd, buffer, buffer_size);
if (written != (ssize_t)buffer_size) {
printf("写入失败\n");
close(fd);
unlink(filename);
free(buffer);
return -1;
}
}
end_time = get_current_time_us();
close(fd);
unlink(filename);
free(buffer);
result->execution_time_us = end_time - start_time;
result->operation_count = operation_count;
result->throughput_ops = (double)operation_count / (result->execution_time_us / 1000000.0);
result->average_latency_us = (double)result->execution_time_us / operation_count;
printf("同步I/O测试完成\n");
return 0;
}
/**
* io_uring异步I/O性能测试
*/
int test_io_uring_performance(performance_result_t *result) {
struct io_uring ring;
const int operation_count = 1000;
const size_t buffer_size = 4096;
char **buffers;
long long start_time, end_time;
int ret;
printf("执行io_uring异步I/O性能测试...\n");
// 初始化io_uring
ret = io_uring_queue_init(256, &ring, 0);
if (ret < 0) {
printf("io_uring初始化失败: %s\n", strerror(-ret));
return -1;
}
// 分配缓冲区
buffers = malloc(operation_count * sizeof(char*));
if (!buffers) {
io_uring_queue_exit(&ring);
return -1;
}
for (int i = 0; i < operation_count; i++) {
buffers[i] = malloc(buffer_size);
if (!buffers[i]) {
// 清理已分配的缓冲区
for (int j = 0; j < i; j++) {
free(buffers[j]);
}
free(buffers);
io_uring_queue_exit(&ring);
return -1;
}
// 填充测试数据
for (size_t j = 0; j < buffer_size; j++) {
buffers[i][j] = 'A' + (i + j) % 26;
}
}
// 创建测试文件
const char *filename = "async_test.dat";
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("创建测试文件失败");
// 清理缓冲区
for (int i = 0; i < operation_count; i++) {
free(buffers[i]);
}
free(buffers);
io_uring_queue_exit(&ring);
return -1;
}
start_time = get_current_time_us();
// 提交异步写入操作
int submitted = 0;
for (int i = 0; i < operation_count; i++) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
if (!sqe) {
printf("获取SQE失败\n");
break;
}
io_uring_prep_write(sqe, fd, buffers[i], buffer_size, i * buffer_size);
sqe->user_data = i;
submitted++;
// 定期提交操作
if (submitted % 32 == 0 || i == operation_count - 1) {
ret = io_uring_submit(&ring);
if (ret < 0) {
printf("提交操作失败: %s\n", strerror(-ret));
break;
}
}
}
printf("提交了 %d 个异步操作\n", submitted);
// 等待所有操作完成
int completed = 0;
while (completed < submitted) {
struct io_uring_cqe *cqe;
ret = io_uring_wait_cqe(&ring, &cqe);
if (ret < 0) {
printf("等待完成事件失败: %s\n", strerror(-ret));
break;
}
completed++;
io_uring_cqe_seen(&ring, cqe);
}
end_time = get_current_time_us();
printf("完成了 %d 个异步操作\n", completed);
// 清理资源
close(fd);
unlink(filename);
for (int i = 0; i < operation_count; i++) {
free(buffers[i]);
}
free(buffers);
io_uring_queue_exit(&ring);
result->execution_time_us = end_time - start_time;
result->operation_count = completed;
result->throughput_ops = (double)completed / (result->execution_time_us / 1000000.0);
result->average_latency_us = (double)result->execution_time_us / completed;
printf("io_uring异步I/O测试完成\n");
return 0;
}
/**
* 演示性能对比测试
*/
int demo_performance_comparison() {
performance_result_t sync_result = {0};
performance_result_t async_result = {0};
printf("=== io_uring vs 同步I/O 性能对比 ===\n");
// 设置测试结果名称
sync_result.test_name = "同步I/O";
async_result.test_name = "io_uring异步I/O";
// 执行同步I/O测试
printf("1. 执行同步I/O测试:\n");
if (test_sync_io_performance(&sync_result) != 0) {
printf(" 同步I/O测试失败\n");
return -1;
}
printf(" 测试完成\n");
// 执行io_uring测试
printf("\n2. 执行io_uring异步I/O测试:\n");
if (test_io_uring_performance(&async_result) != 0) {
printf(" io_uring测试失败\n");
return -1;
}
printf(" 测试完成\n");
// 显示测试结果
printf("\n=== 性能测试结果 ===\n");
printf("%-20s %-15s %-15s %-15s %-15s\n",
"测试类型", "操作次数", "耗时(μs)", "吞吐量(ops/s)", "平均延迟(μs)");
printf("%-20s %-15s %-15s %-15s %-15s\n",
"--------", "--------", "--------", "------------", "------------");
printf("%-20s %-15d %-15lld %-15.0f %-15.2f\n",
sync_result.test_name,
sync_result.operation_count,
sync_result.execution_time_us,
sync_result.throughput_ops,
sync_result.average_latency_us);
printf("%-20s %-15d %-15lld %-15.0f %-15.2f\n",
async_result.test_name,
async_result.operation_count,
async_result.execution_time_us,
async_result.throughput_ops,
async_result.average_latency_us);
// 性能对比分析
printf("\n=== 性能对比分析 ===\n");
if (sync_result.execution_time_us > 0 && async_result.execution_time_us > 0) {
double time_improvement = (double)sync_result.execution_time_us / async_result.execution_time_us;
double throughput_improvement = async_result.throughput_ops / sync_result.throughput_ops;
double latency_reduction = (sync_result.average_latency_us - async_result.average_latency_us) /
sync_result.average_latency_us * 100;
printf("执行时间对比: %.2f 倍提升\n", time_improvement);
printf("吞吐量对比: %.2f 倍提升\n", throughput_improvement);
printf("平均延迟减少: %.1f%%\n", latency_reduction);
}
// 显示优势分析
printf("\n=== 优势分析 ===\n");
printf("1. io_uring优势:\n");
printf(" ✓ 零拷贝数据传输\n");
printf(" ✓ 减少系统调用次数\n");
printf(" ✓ 提高I/O并发性能\n");
printf(" ✓ 更好的CPU利用率\n");
printf("\n2. 适用场景:\n");
printf(" ✓ 高并发网络服务器\n");
printf(" ✓ 大文件传输应用\n");
printf(" ✓ 实时数据处理\n");
printf(" ✓ 数据库存储引擎\n");
printf("\n3. 性能优化建议:\n");
printf(" ✓ 合理设置环形缓冲区大小\n");
printf(" ✓ 批量提交I/O操作\n");
printf(" ✓ 使用适当的等待策略\n");
printf(" ✓ 监控系统资源使用\n");
return 0;
}
int main() {
return demo_performance_comparison();
}
io_uring 使用注意事项
系统要求:
- 内核版本: 需要Linux 5.1或更高版本
- 架构支持: 支持所有主流架构
- 编译要求: 需要liburing库支持
初始化选项:
- IORING_SETUP_IOPOLL: 启用I/O轮询模式
- IORING_SETUP_SQPOLL: 启用提交队列轮询
- IORING_SETUP_SQ_AFF: 设置提交队列CPU亲和性
- IORING_SETUP_CQSIZE: 设置完成队列大小
错误处理:
- 负返回值: 表示错误码
- errno设置: 传统错误码机制
- 完成事件: 通过cqe->res返回结果
性能考虑:
- 缓冲区大小: 合理设置环形缓冲区大小
- 批量操作: 批量提交提高效率
- 内存管理: 避免频繁的内存分配
- CPU亲和性: 考虑CPU绑定优化
安全考虑:
- 权限检查: 确保有足够的权限
- 资源限制: 避免消耗过多系统资源
- 输入验证: 验证所有输入参数
- 错误恢复: 妥善处理各种错误情况
最佳实践:
- 环境检查: 使用前检查内核支持
- 参数验证: 验证所有输入参数
- 错误处理: 妥善处理各种错误
- 资源管理: 及时释放分配的资源
- 性能监控: 监控性能指标并优化
io_uring vs 传统AIO对比
传统AIO限制:
// 传统AIO接口
#include <linux/aio_abi.h>
int io_setup(unsigned nr_events, aio_context_t *ctxp);
int io_destroy(aio_context_t ctx);
int io_submit(aio_context_t ctx, long nr, struct iocb *ios[]);
int io_cancel(aio_context_t ctx, struct iocb *iocb, struct io_event *result);
int io_getevents(aio_context_t ctx, long min_nr, long nr,
struct io_event *events, struct timespec *timeout);
io_uring优势:
// io_uring接口
#include <liburing.h>
int io_uring_queue_init(unsigned entries, struct io_uring *ring, unsigned flags);
int io_uring_queue_exit(struct io_uring *ring);
int io_uring_submit(struct io_uring *ring);
int io_uring_wait_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr);
性能对比数据
系统调用开销:
- 传统AIO: 每次操作需要多个系统调用
- io_uring: 批量操作减少系统调用次数
内存拷贝:
- 传统AIO: 需要多次内存拷贝
- io_uring: 零拷贝数据传输
并发性能:
- 传统AIO: 并发性能有限
- io_uring: 高并发性能优异
常见使用场景
1. 网络服务器:
// 高性能网络服务器
struct io_uring ring;
io_uring_queue_init(4096, &ring, 0);
// 批量处理网络请求
for (int i = 0; i < connections; i++) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_recv(sqe, conn_fd[i], buffer[i], buffer_size, 0);
}
io_uring_submit(&ring);
2. 存储系统:
// 高性能存储系统
struct io_uring ring;
io_uring_queue_init(8192, &ring, IORING_SETUP_IOPOLL);
// 批量存储操作
for (int i = 0; i < io_count; i++) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_write(sqe, fd, data[i], size[i], offset[i]);
}
io_uring_submit(&ring);
3. 数据库引擎:
// 数据库存储引擎
struct io_uring ring;
io_uring_queue_init(2048, &ring, 0);
// 并发数据页读写
for (int i = 0; i < pages; i++) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fd, page_buffer[i], page_size, page_offset[i]);
}
io_uring_submit(&ring);
总结
io_uring 是Linux系统中先进的异步I/O框架,提供了:
- 高性能: 显著优于传统AIO的性能
- 易用性: 简化的API设计
- 灵活性: 丰富的操作类型支持
- 可扩展性: 支持大规模并发操作
通过合理使用io_uring,可以构建高性能的I/O密集型应用。在实际应用中,需要注意内核版本要求、错误处理和性能优化等关键问题。