io_uring 系统调用及示例

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 使用注意事项

系统要求:

  1. 内核版本: 需要Linux 5.1或更高版本
  2. 架构支持: 支持所有主流架构
  3. 编译要求: 需要liburing库支持

初始化选项:

  1. IORING_SETUP_IOPOLL: 启用I/O轮询模式
  2. IORING_SETUP_SQPOLL: 启用提交队列轮询
  3. IORING_SETUP_SQ_AFF: 设置提交队列CPU亲和性
  4. IORING_SETUP_CQSIZE: 设置完成队列大小

错误处理:

  1. 负返回值: 表示错误码
  2. errno设置: 传统错误码机制
  3. 完成事件: 通过cqe->res返回结果

性能考虑:

  1. 缓冲区大小: 合理设置环形缓冲区大小
  2. 批量操作: 批量提交提高效率
  3. 内存管理: 避免频繁的内存分配
  4. CPU亲和性: 考虑CPU绑定优化

安全考虑:

  1. 权限检查: 确保有足够的权限
  2. 资源限制: 避免消耗过多系统资源
  3. 输入验证: 验证所有输入参数
  4. 错误恢复: 妥善处理各种错误情况

最佳实践:

  1. 环境检查: 使用前检查内核支持
  2. 参数验证: 验证所有输入参数
  3. 错误处理: 妥善处理各种错误
  4. 资源管理: 及时释放分配的资源
  5. 性能监控: 监控性能指标并优化

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框架,提供了:

  1. 高性能: 显著优于传统AIO的性能
  2. 易用性: 简化的API设计
  3. 灵活性: 丰富的操作类型支持
  4. 可扩展性: 支持大规模并发操作

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

此条目发表在未分类分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注