io_uring 系统调用及示例

io_uring 系统调用详解

  1. 函数介绍

io_uring 是Linux 5.1引入的高性能异步I/O框架,提供了一种现代化的异步I/O接口。相比传统的AIO(异步I/O),io_uring具有更好的性能、更低的系统调用开销和更丰富的功能。它使用共享内存环形缓冲区实现用户空间和内核空间的高效通信。

  1. 函数原型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#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);

  1. 功能

io_uring 提供了完整的异步I/O解决方案,支持文件I/O、网络I/O、文件操作等多种操作类型。它通过共享内存环形缓冲区实现零拷贝的数据传输,显著提高了I/O性能。

  1. 参数说明

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: 完成事件指针

  1. 返回值
  • 成功: 返回非负值或0

  • 失败: 返回负的错误码

  1. 相似函数,或关联函数
  • io_setup/io_destroy: 传统的AIO接口

  • io_submit/io_cancel: 传统的AIO提交和取消

  • io_getevents: 传统的AIO事件获取

  • aio_read/aio_write: POSIX AIO接口

  • epoll_wait/poll: 传统的I/O多路复用

  1. 示例代码

示例1:基础io_uring使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#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&#91;256];
ssize_t bytes_read = read(test_fd, read_buffer, sizeof(read_buffer) - 1);
if (bytes_read > 0) {
read_buffer&#91;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操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#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&#91;file_count];
char filenames&#91;file_count]&#91;32];

for (int i = 0; i < file_count; i++) {
snprintf(filenames&#91;i], sizeof(filenames&#91;i]), "batch_test_%d.txt", i);
file_fds&#91;i] = open(filenames&#91;i], O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (file_fds&#91;i] == -1) {
perror(" 创建文件失败");
// 清理已创建的文件
for (int j = 0; j < i; j++) {
close(file_fds&#91;j]);
unlink(filenames&#91;j]);
}
io_uring_queue_exit(&ring);
return -1;
}
printf(" 创建文件 %d: %s\n", i, filenames&#91;i]);
}

// 准备批量写入操作
printf("\n3. 准备批量写入操作:\n");
char *test_data&#91;file_count];
int submitted_ops = 0;

for (int i = 0; i < file_count; i++) {
// 分配测试数据
test_data&#91;i] = malloc(256);
if (!test_data&#91;i]) {
perror(" 分配测试数据失败");
// 清理资源
for (int j = 0; j <= i; j++) {
if (test_data&#91;j]) free(test_data&#91;j]);
if (j < file_count) {
close(file_fds&#91;j]);
unlink(filenames&#91;j]);
}
}
io_uring_queue_exit(&ring);
return -1;
}

snprintf(test_data&#91;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&#91;i], test_data&#91;i], strlen(test_data&#91;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&#91;i]);

// 重新打开文件读取
int read_fd = open(filenames&#91;i], O_RDONLY);
if (read_fd != -1) {
struct stat st;
if (fstat(read_fd, &st) == 0) {
printf(" 文件 %s: 大小 %ld 字节\n", filenames&#91;i], st.st_size);
}
close(read_fd);
}
}

// 清理资源
printf("\n7. 清理资源:\n");
for (int i = 0; i < file_count; i++) {
free(test_data&#91;i]);
unlink(filenames&#91;i]);
}

io_uring_queue_exit(&ring);
printf(" ✓ 所有资源清理完成\n");

return 0;
}

int main() {
return demo_batch_io_operations();
}

示例3:文件操作演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#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&#91;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&#91;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&#91;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演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#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&#91;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:性能对比测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#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&#91;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&#91;i] = malloc(buffer_size);
if (!buffers&#91;i]) {
// 清理已分配的缓冲区
for (int j = 0; j < i; j++) {
free(buffers&#91;j]);
}
free(buffers);
io_uring_queue_exit(&ring);
return -1;
}

// 填充测试数据
for (size_t j = 0; j < buffer_size; j++) {
buffers&#91;i]&#91;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&#91;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&#91;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&#91;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或更高版本

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

架构支持: 支持所有主流架构

编译要求: 需要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限制:

1
2
3
4
5
6
7
8
9
// 传统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&#91;]);
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优势:

1
2
3
4
5
6
7
// 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. 网络服务器:

1
2
3
4
5
6
7
8
9
10
11
12
// 高性能网络服务器
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&#91;i], buffer&#91;i], buffer_size, 0);
}

io_uring_submit(&ring);

2. 存储系统:

1
2
3
4
5
6
7
8
9
10
11
12
// 高性能存储系统
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&#91;i], size&#91;i], offset&#91;i]);
}

io_uring_submit(&ring);

3. 数据库引擎:

1
2
3
4
5
6
7
8
9
10
11
12
// 数据库存储引擎
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&#91;i], page_size, page_offset&#91;i]);
}

io_uring_submit(&ring);

总结

io_uring 是Linux系统中先进的异步I/O框架,提供了:

高性能: 显著优于传统AIO的性能

易用性: 简化的API设计

灵活性: 丰富的操作类型支持

可扩展性: 支持大规模并发操作

通过合理使用io_uring,可以构建高性能的I/O密集型应用。在实际应用中,需要注意内核版本要求、错误处理和性能优化等关键问题。

data-ad-format="auto" data-full-width-responsive="true">