io_uring 用法分析 I :异步 IO ,Windows IOCP 接口与 Proactor 模式

在具体研究 io_uring 之前,有必要了解之前的 aio,包括 glib 实现的 POSIX aio 和 Linux 后来提供的只支持  O_DIRECT 的 Linux aio (不支持 socket 因为 socket 不能 O_DIRECT)。不然我实在看不懂 io_uring 目前的资料(和 epoll 铺天盖地的资料实在是没法比啊)。

首先是基本的情况,由于 Linux 早期不支持 Posix ais,所以实际 glib 是在用户态模拟了一个的,实际原理是通过多线程后台同步读写,然后自己维护一个 buffer,然而性能垃圾而且有 bug,只能说异步 IO 的实现有点复杂了属于,大牛都写不出个好用的来(M$ IOCP下面研究一下)

首先有必要搞明白 Proactor 和 Reactor 模型的到底区别在哪里?

One thread per client

  • 最古老的复用是用线程/进程复用,由 kernel 来调度公平地为每个用户服务。如果要做成千上万的并发连接的话,尤其是长连接,就涉及这么多的进程线程调度的开销。
  • 当然,one thread per client 也是会阻塞挂起的。

Reactor

  • 通过 master + workers 的 Reactor 方案则是通过数据结构来维护所有的用户的信息,让特定的 workers 去给他服务。
  • 这里就涉及要用定时器来单线程(尽管有固定数量的多个工作进程(或者线程也行),但是他们是单线程为多个用户服务的)调度每个用户了。
  • 这个过程中如果涉及了阻塞的系统调用,基本的方法是再次注册一个等待事件到 epoll wait 的事件集合中,然后换一个回调函数。
  • 回调函数在 Reactor 的概念是这样的,他就是一个阻塞事件就绪之后调用的东西,比如一个 fd,如果能读写了,他就会醒来,此时 Reactor 会根据 hashmap dispatch 这个回调函数给一个工作线程运行。
  • 此时工作线程运行这个 read 或者 write 就不会阻塞了。
  • 当然,还有一种情况,如果读了一半又要阻塞了怎么办?(由于我们必须让工作线程服务多个用户,所以这个必须是非阻塞调用),或者说用户人态定时的 expiration 到了。
  • 所以一般我们绑定这个 Callback 是一个状态机来的,他必须是保留着状态的,这样才能重新注回到 epoll wait 里面(就涉及要打断正在 blocking 的 epoll wait),并且因为保留了状态(比如说用一个 Object)所以回调函数还是同一个。

Proactor 复习

  • 我之前搞不明白 Proactor 这个有什么区别。其实最直观的区别就是 Proactor 的回调触发是说异步读写 Complete 了的,而 Reactor 回调的时候,读写还没有开始。所以这个东西和 DMA 是差不多的机制的。但是问题是,这样整个架构不是没什么区别吗?无非是去掉了要调用读写的部分,而数据已经准备好了而已。
  • 当然一个区别是,我们不需要再自己调度了,不需要自己维护定时器了,因为事情实际已经委托给一个内核线程来进行读写了。
  • 由于实际网上根本找不到具体讲这个怎么做的(只有一大堆讲个大概原理的),所以只能看各大网络库的实际实现依赖的 OS 接口了,就是微软的 IOCP I/O Completion Ports - Win32 apps | Microsoft Docs。当然,只需要学一下 boost  的 asio 就能明白了,以及 Proactor 的论文还有那本书 POSA2。不过既然都要看 IOCP,就从 IOCP 提供的 API 去看怎么实现 Proactor 吧。
  • 先复习一下 asio 是什么样的架构,以及他对应的部件先吧
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值