资讯专栏INFORMATION COLUMN

用 io_uring 替代 epoll 实现高速 polling

mengera88 / 3182人阅读

摘要:前面的文章说到是中最新的原生异步实现,实际上也支持,是良好的替代品。拿到之后,使用初始化指针。添加完需要的请求后使用统一提交使用获取完成情况等操作与标准异步请求一致。拿做最有用的一点是把和的完成事件做统一监听和处理。

前面的文章说到 io_uring 是 Linux 中最新的原生异步 I/O 实现,实际上 io_uring 也支持 polling,是良好的 epoll 替代品。

API

使用 io_uring 来 poll 一个 fd 很简单。首先初始化 io_uring 对象(io_uring_queue_init),拿到 sqe(io_uring_get_sqe)是所有 io_uring 操作都必要的,前文已经介绍这里不做过多说明。拿到 sqe 之后,使用 io_uring_prep_poll_add 初始化 sqe 指针。

static inline void io_uring_prep_poll_add(struct io_uring_sqe *sqe, int fd,
                      short poll_mask);

第一个参数就是前面获得的 sqe 指针;第二个参数是你要 poll 的文件描述符;第三个是标志位,这里 io_uring 没有引入新的标志(宏),而是沿用了 poll(2) 定义的标志,如 POLLIN、POLLOUT 等。

如其他 I/O 请求一样,每个 sqe 都可以设置一个用户自己的值在里面,使用 io_uring_sqe_set_data

可以看到一次只能添加一个 poll 请求。如果有多个 fd,那么重复调用 io_uring_get_sqe 获取多个 sqe 指针分别 io_uring_prep_poll_add 即可。io_uring_get_sqe 不是系统调用不会进入内核,io_uring_prep_poll_add 则是简单的结构体参数赋值,所以没有速度问题。

添加完需要的请求后使用 io_uring_submit 统一提交、使用 io_uring_peek_cqe 获取完成情况等操作与标准异步 I/O 请求一致。

使用 io_uring 做 polling 与 epoll、poll 的默认模式有一个很大的区别就是 io_uring 的 polling 始终工作在 one-shot 模式下(等同于 epoll 的 EPOLLONESHOT),即一旦某个 poll 操作完成,用户必须重新提交 poll 请求否则不会触发新的事件,这样保证每个 poll 请求有且只有一个响应。然后既然是 one-shot 模式,也就没有类似 epoll 中的 LT、ET 模式之分

清除进行中的 polling 请求使用 io_uring_prep_poll_remove

static inline void io_uring_prep_poll_remove(struct io_uring_sqe *sqe,
                         void *user_data);

也是需要 sqe 然后 submit。可以看到这个函数很特别的直接需要 user_data 参数。内核是在用之前提交的 user_data 和你现在指定的 user_data 做对比,删除值相等的请求。

示例

在网络编程中最开始的需求就是异步监听客户端接入(O_NONBLOCK accept),这也是好多 epoll 的代码示例。用 io_uring 如下:

int sockfd = socket(...);
bind(...);
listen(...);

struct io_uring ring;
io_uring_queue_init(32, &ring, 0);

struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_poll_add(sqe, sockfd, POLLIN);
io_uring_submit(&ring);

struct io_uring_cqe *cqe;
io_uring_wait_cqe(&ring, &cqe);

int clientfd = accept(sockfd, ...);

个人感觉如果拿 io_uring 纯做 polling 的话没有什么优势。拿 io_uring 做 polling 最有用的一点是把 polling 和 aio 的完成事件做统一监听和处理。想象拿到 clientfd 之后就可以立即使用 io_uring_prep_readv 读取请求体,同时又可以再使用 io_uring_prep_poll_add 接受其他客户端接入,这样才是真正的异步编程。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/63937.html

相关文章

  • 原生的 Linux 异步文件操作,io_uring 尝鲜体验

    摘要:后来在引入了真正的内核级别支持的异步实现,但是它只支持,只支持磁盘文件读写,而且对文件大小还有限制,总之各种麻烦。完成请求都是异步操作,不会阻塞当前线程。 Linux异步IO的历史 异步IO一直是 Linux 系统的痛。Linux 很早就有 POSIX AIO 这套异步IO实现,但它是在用户空间自己开用户线程模拟的,效率极其低下。后来在 Linux 2.6 引入了真正的内核级别支持的异...

    gekylin 评论0 收藏0
  • Linux IO模式及 select、poll、epoll详解

    摘要:因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。把进程的移入相应的队列,如就绪在某事件阻塞等队列。恢复处理机上下文。但,,本质上都是同步,因为他们都需要在读写事件就绪后自 注:本文是对众多博客的学习和总结,可能存在理解错误。请带着怀疑的眼光,同时如果有错误希望能指出。 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同...

    ytwman 评论0 收藏0
  • Linux IO模式及 select、poll、epoll详解

    摘要:因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。把进程的移入相应的队列,如就绪在某事件阻塞等队列。恢复处理机上下文。但,,本质上都是同步,因为他们都需要在读写事件就绪后自 注:本文是对众多博客的学习和总结,可能存在理解错误。请带着怀疑的眼光,同时如果有错误希望能指出。 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同...

    CHENGKANG 评论0 收藏0
  • 手把手写C++服务器(31):服务器性能提升关键——IO复技术【两万字长文】

    摘要:前面几讲手撕了网关服务器回显服务器服务的代码,但是这几个一次只能监听一个文件描述符,因此性能非常原始低下。复用能使服务器同时监听多个文件描述符,是服务器性能提升的关键。表示要操作的文件描述符,指定操作类型,指定事件。  本系列文章导航: 手把手写C++服务器(0):专栏文章-汇总导航【更...

    big_cat 评论0 收藏0
  • IO多路复(一)-- Select、Poll、Epoll

    摘要:多路复用的概念多路复用是一种机制,可以用来监听多种描述符,如果其中任意一个描述符处于就绪的状态,就会返回消息给对应的进程通知其采取下一步的操作。 在上一篇博文中提到了五种IO模型,关于这五种IO模型可以参考博文IO模型浅析-阻塞、非阻塞、IO复用、信号驱动、异步IO、同步IO,本篇主要介绍IO多路复用的使用和编程。 IO多路复用的概念 多路复用是一种机制,可以用来监听多种描述符,如果其...

    Kylin_Mountain 评论0 收藏0

发表评论

0条评论

mengera88

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<