xiaohanliang
OS
OS
  • hi
  • PROCESS
    • 0. 你的程序是怎么用内存的
    • 1. 为什么内存要区分堆与栈
    • 2. 什么叫你的程序
    • 3. 搞玄学?看看进程切换
    • 4. 进程是怎样调度的
    • 5. 理解进程线程有啥用
    • 6. 没有人真正见过的进程通信
    • 7. [WIP]mutex的起源CAS
    • 8. [WIP]mutex的下一步信号量
    • 9. [WIP]如何人为制造死锁
    • 10. 怎么什么东西都是fd
    • 11. IO各种模型
    • 12. Epoll内部是怎么工作的
  • NETWORK DEVICES
    • 1. 一个新的namesapce
    • 2. veth对讲机
    • 3. 如何靠网桥连接对讲机
    • 4. 左耳进右耳出的tun设备
    • 5. 如何用iptables改包头
    • 6. 在ip报头上再包个头
    • 7.如何用vxlan隧道分割局域网
    • 8. 通过多播组的方式获取mac
    • 9. 自动维护的fdb/arp表
    • 10. [WIP]macvlan网卡
Powered by GitBook
On this page
  • introduction
  • Model1 - BlockingIO
  • Model2 - NonBlockingIO
  • Model3 - MultiplexingIO
  • Model4 - SingnalDrivenIO
  • Model5 - AsynchronousIO
  • 如何区分同步/异步IO

Was this helpful?

  1. PROCESS

11. IO各种模型

Previous10. 怎么什么东西都是fdNext12. Epoll内部是怎么工作的

Last updated 4 years ago

Was this helpful?

introduction

我知道我讲了一些玄学东西, 上一节在对比进程/线程的时候我特意留了一嘴说redis/memcached, 立刻我就意识到如果说了这两者的线程模型, 那么是不可能说他们的IO模型的, 因为他们所表现出来的特性是由线程与IO两种模型结合在一起决定的.

我们从一个最简单的情况开始讲, 假设你新建了一个socket监听某端口 (tcpudp都行), 如果有人给你发消息, 消息就会从网卡哪儿先被拷贝到内核缓冲区里, 然后你从内核区域里[读]到进程的虚拟内存下. socket描述符你已经有了, 如果你现在就要读, 会发生什么呢? 这就是IO模型最核心的问题 → 会发生什么

Model1 - BlockingIO

在你什么都不做的情况下, 一个socket默认是堵塞型的, 意思就是如果你现在通过 recvfrom 函数从这个socket里读数据, 如果有数据就直接返回, 如果没有数据就一直卡在哪儿, 一直卡到有数据再返回 (消息从网卡拷贝到内核里)

Model2 - NonBlockingIO

但你也可以选择把这个socket设置成非阻塞模式, 此时在网卡没有收到数据之前, 你一调用recvfrom就会立刻返回并报错, 你就在一个for循环里一直查(这种反复查的动作我们叫它polling), 直到网卡已经收到数据了, 此时不立刻报错了, 内核开始将数据拷贝到内核buffer里, 然后还给你的程序.

非阻塞IO确实不会产生恶心的阻塞, 但是为什么很少见到呢? 因为如果你是阻塞状态, CPU就不会让你跑, 但是在非阻塞的IO下, CPU还得让你一直跑着, 效果都是收信息, 后者还得浪费CPU的时间

Model3 - MultiplexingIO

这个模型不是针对某单个socket了, 这个模型处理一组socket, 以select函数为例, select函数接受一组socket, 函数调用以后就卡着, 直到里面某一个socket变的可读了就返回这个可读的socket并同时解除阻塞.

那么既然你已经持有一个可读的socket了, 你就可以通过函数 recvfrom 去里面读东西了. multiplexing 里面大有玩头, 另类玩法比如poll/epoll的对比(这个我们会在下一节讲), 正是这个原因促成了redis如此出色的表现

Model4 - SingnalDrivenIO

既然内核知道什么时候可读, 那为什么不找一种方式来通知我们呢? 信号驱动IO要求你先通过sigaction函数为这个socket注册上信号, 等网卡收到数据了, 也拷贝到内核buffer里了, 这个时候通过一个SIGIO信号告诉你的程序, 这个时候你的程序再来通过 recvfrom 的方式去取

Model5 - AsynchronousIO

这种IO模型是5个模型里唯一真正异步IO的模型, 我们首先通过 aio_read 的方式传入

  • 一个socket(fd)

  • 一个byte数组(buffer) + 数组长度

  • 就绪以后如何通知我们 (比如golang的 done<-struct{}{})

接下来是纯自动的: 网卡收到数据 → 拷贝到内核缓冲区 → 从内核缓冲区读到你的byte数组里 → 通知你, 纯自动纯的, 这么纯自动的东西为什么很少用呢? 因为不是很多系统都支持AsyncIO的

如何区分同步/异步IO

  • "异步的" IO: 在调用读请求的时候不会产生阻塞, 仅有最后一种Model5- AIO是符合要求的

  • "同步的" IO: 在调用读请求的时候会产生阻塞, 直到拷贝到byte数组的动作完全搞定, 前四种全都是同步的, 因为尽管通知(内核buffer已就绪的)机制各有不同, 但是实际从内核buffer拷贝到用户byte数组的时候, 还是阻塞的, 一直阻塞到拷贝完全ok位置

这是一篇非常好的文章, 阅读完我只用了半小时

但感觉, 非常的澄澈

本文译自:

这里