使用 io_uring
实现异步写入 16MB-64MB 数据到文件(完整代码)
io_uring
是 Linux 高性能异步 I/O 框架,适用于大文件写入场景。以下是一个完整示例,将 16MB~64MB 的随机数据异步写入文件,并确保高效性和正确性。
1. 代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <liburing.h>
#include <sys/stat.h>
#define BUF_SIZE (16 * 1024 * 1024) // 16MB 缓冲区(可调整至64MB)
#define FILE_NAME "large_file.bin"
// 初始化io_uring
int setup_uring(struct io_uring *ring, unsigned entries) {
int ret = io_uring_queue_init(entries, ring, 0);
if (ret < 0) {
perror("io_uring_queue_init");
exit(EXIT_FAILURE);
}
return ret;
}
// 生成随机数据
void generate_data(char *buf, size_t size) {
for (size_t i = 0; i < size; i++) {
buf[i] = rand() % 256; // 填充随机字节
}
}
// 异步写入文件
void async_write(struct io_uring *ring, int fd, char *buf, size_t size) {
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
if (!sqe) {
fprintf(stderr, "Failed to get SQE\n");
exit(EXIT_FAILURE);
}
io_uring_prep_write(sqe, fd, buf, size, 0); // 异步写入
io_uring_sqe_set_data(sqe, buf); // 关联缓冲区(用于后续释放)
io_uring_submit(ring); // 提交请求
}
int main() {
struct io_uring ring;
int fd;
char *buf;
size_t size = BUF_SIZE;
// 1. 初始化io_uring
setup_uring(&ring, 8); // 8个SQE(可调整)
// 2. 创建文件并分配缓冲区
fd = open(FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
buf = malloc(size);
if (!buf) {
perror("malloc");
exit(EXIT_FAILURE);
}
// 3. 生成随机数据并异步写入
generate_data(buf, size);
async_write(&ring, fd, buf, size);
// 4. 等待写入完成
struct io_uring_cqe *cqe;
int ret = io_uring_wait_cqe(&ring, &cqe);
if (ret < 0) {
perror("io_uring_wait_cqe");
exit(EXIT_FAILURE);
}
if (cqe->res < 0) {
fprintf(stderr, "Write error: %s\n", strerror(-cqe->res));
exit(EXIT_FAILURE);
}
printf("Successfully wrote %zu bytes to %s\n", size, FILE_NAME);
// 5. 清理资源
io_uring_cqe_seen(&ring, cqe); // 标记CQE已处理
io_uring_queue_exit(&ring); // 释放io_uring
free(buf);
close(fd);
return 0;
}
2. 关键点解析
(1)io_uring
核心步骤
- 初始化
io_uring
io_uring_queue_init()
:创建环形队列(SQ/CQ)。- 参数
entries
控制队列大小(影响并发能力)。
- 提交异步写入请求
io_uring_get_sqe()
:获取一个空闲的提交队列项(SQE)。io_uring_prep_write()
:设置异步写入操作。io_uring_submit()
:提交请求到内核。
- 等待完成事件
io_uring_wait_cqe()
:阻塞等待完成事件(CQE)。- 检查
cqe->res
确认写入是否成功。
- 资源释放
io_uring_cqe_seen()
:标记CQE已处理。io_uring_queue_exit()
:释放io_uring
资源。
(2)性能优化建议
- 缓冲区对齐:使用
posix_memalign
分配对齐的内存(减少内核拷贝开销)。posix_memalign((void**)&buf, 4096, size); // 4K对齐
- 批量提交:一次性提交多个写入请求(利用
io_uring
的批处理能力)。 - 轮询模式:启用
IORING_SETUP_SQPOLL
减少系统调用(需root权限)。
(3)扩展至64MB数据
- 修改
BUF_SIZE
为64 * 1024 * 1024
。 - 如果内存不足,可分块写入(每次提交16MB,循环4次)。
3. 编译与运行
gcc -o io_uring_write io_uring_write.c -luring
./io_uring_write
输出示例:
Successfully wrote 16777216 bytes to large_file.bin
4. 验证写入结果
ls -lh large_file.bin # 检查文件大小
md5sum large_file.bin # 验证数据完整性
5. 总结
组件 | 作用 |
---|---|
io_uring | 提供异步I/O接口,避免阻塞线程。 |
SQE/CQE | 提交队列(SQE)和完成队列(CQE)实现高效事件通知。 |
缓冲区管理 | 大内存分配需考虑对齐和分块,避免内存碎片。 |
此代码适用于 大文件写入、数据库日志、高性能存储 等场景,通过异步I/O最大化磁盘吞吐。