阻塞、非阻塞,同步、异步的理解

总结

 

一个IO过程分为两步:数据写入CPU内核,数据从CPU内核写入到进程缓冲区

 

1)BIO与NIO

 

  指的是发起系统调用后,系统调用短时间内无法完成

 

    BIO对应的进程会被CPU置为阻塞状态

 

    NIO则不会阻塞(可以去做其他事情),NIO的进程会隔一段时间来询问一次

 

2)NIO与异步IO的区别

 

  NIO发起系统调用后就会得到返回值(但不一定第一步准备好),第二步会阻塞

 

  AIO发起系统调用后不会得到返回值,而是在整个第一步、第二步全部完成后,基于回调接口得到返回值

 

3)NIO与IO多路复用的区别

 

  NIO是发起系统调用的进程,隔一段时间轮询一次

 

  IO多路复用是有一个线程监听所有的socket,等待第一步数据写入CPU完成,然后响应事件完成第二步。

 

    IO多路复用Java中的实现方式是轮询,poll、select也是轮询

 

    操作系统的实现方式是回调(epoll)

 

 


 

参考:https://leetcode-cn.com/circle/discuss/uHGOZo/

1.用户空间和内存空间

  用户空间和内核空间操作系统为了支持多个应用同时运行,保证进程相对独立。操作系统内核需要拥有高于普通进程的权限。
  内核空间可以用来控制用户空间的进程的调度和切换,用户空间用来实现进程的隔离?

 

2.进程切换的过程

 

 

  • 当一个程序正在执行的过程中,中断(interrupt) 或 系统调用(system call) 发生可以使得 CPU 的控制权会从当前进程转移到操作系统内核。
  • 操作系统内核负责保存进程 i 在 CPU 中的上下文(程序计数器,寄存器)到 PCBi (操作系统分配给进程的一个内存块)中。
  • 从 PCBj 取出进程 j 的CPU 上下文,将 CPU 控制权转移给进程 j ,开始执行进程 j 的指令。
    • 附:系统中存放进程的管理和控制信息的数据结构称为进程控制块(PCB Process Control Block)
    • 当OS要调度某进程执行时,要从该进程的PCB中查处其现行状态及优先级;在调度到某进程后,要根据其PCB中所保存的处理机状态信息,设置该进程恢复运行的现场,并根据其PCB中的程序和数据的内存始址,找到其程序和数据;进程在执行过程中,当需要和与之合作的进程实现同步,通信或者访问文件时,也都需要访问PCB;当进程由于某种原因而暂停执行时,又须将器断点的处理机环境保存在PCB中。
    • 在进程的整个生命期中,系统总是通过PCB对进程进行控制的,即系统是根据进程的PCB而不是任何别的什么而感知到该进程的存在的。所以说,PCB是进程存在的唯一标志。

 

几个底层概念的通俗(不严谨)解释:
    中断(interrupt)
        CPU 微处理器有一个中断信号位,在每个CPU时钟周期的末尾, CPU会去检测那个中断信号位是否有中断信号到达,如果有,则会根据中断优先级决定是否要暂停当前执行的指令,转而去执行处理中断的指令。(其实就是 CPU 层级的 while 轮询)
    时钟中断(Clock Interrupt)
        一个硬件时钟会每隔一段(很短)的时间就产生一个中断信号发送给 CPU,CPU 在响应这个中断时,就会去执行操作系统内核的指令,继而将 CPU 的控制权转移给了操作系统内核,可以由操作系统内核决定下一个要被执行的指令。
    系统调用(system call)
        system call 是操作系统提供给应用程序的接口。用户通过调用 systemcall 来完成那些需要操作系统内核进行的操作,例如硬盘,网络接口设备的读写等。

 

3.进程阻塞的理解

  • New. 进程正在被创建.
  • Running. 进程的指令正在被执行
  • Waiting. 进程正在等待一些事件的发生(例如 I/O 的完成或者收到某个信号)
  • Ready. 进程在等待被操作系统调度
  • Terminated. 进程执行完毕(可能是被强行终止的)

 “阻塞”是指进程在发起了一个系统调用(System Call) 后,由于该系统调用的操作不能立即完成,需要等待一段时间,于是内核将进程挂起为等待 (waiting)状态,以确保它不会被调度执行,占用 CPU 资源。

  • 在任意时刻,一个 CPU 核心上(processor)只可能运行一个进程。

 

4.非阻塞 & 异步

阻塞和非阻塞描述的是进程的一个操作是否会使得进程转变为“等待”的状态

  • 计算机物理通信:基本都是异步完成的,即发出请求后,等待 I/O 设备的中断信号后,再来读取相应的设备缓冲区
  • 操作系统为用户级提供的调用接口,有以下两类
    • 阻塞式系统调用:阻塞式的调用,使得应用级代码的编写更容易(代码的执行顺序和编写顺序是一致的)
    • 非阻塞式系统调用:非阻塞调用不会挂起调用程序,而是会立即返回一个值,表示有多少bytes 的数据被成功读取(或写入)

异步处理:

  • asychronous system call 也是会立即返回,不会等待 I/O 操作的完成,应用程序可以继续执行其他的操作,等到 I/O 操作完成了以后,操作系统会通知调用进程(设置一个用户空间特殊的变量值 或者 触发一个 signal 或者 产生一个软中断 或者 调用应用程序的回调函数)。

此处,非阻塞I/O 系统调用( nonblocking system call ) 和 异步I/O系统调用 (asychronous system call)的区别是:

1) 一个非阻塞I/O 系统调用 read() 操作立即返回的是任何可以立即拿到的数据,可以是完整的结果,也可以是不完整的结果,还可以是一个空值。而异步I/O系统调用 read()结果必须是完整的,但是这个操作完成的通知可以延迟到将来的一个时间点。

 2)操作系统的IO过程分为两步:

(1)系统调用( 硬盘,网络接口设备的读写 )后,内核等待返回数据,将数据准备好
(2)数据从内核复制到用户空间(内存操作???)
  • NIO中需要一个selector线程来建通所有的socket,第一步等待数据过程不阻塞,第二部数据转移过程还是会阻塞(  “阻塞”是指进程在发起了一个系统调用(System Call) 后,由于该系统调用的操作不能立即完成,需要等待一段时间,于是内核将进程挂起为等待 (waiting)状态,以确保它不会被调度执行,占用 CPU 资源。)
  • AIO中不需要监听的线程,第一步第二步均不阻塞,两步完成后通过回调机制通知对应的进程(用户空间)

 

5.NIO(一般的NIO是隔一段时间询问一次)
  • 第一个阶段是非阻塞的
  • 第二个阶段是阻塞的
   
 
 
6.操作系统底层的IO多路复用实现(select\poll是轮询,epoll是回调)
  • 三者的区别
    • select:
      • 可以跨任何操作系统
      • timeout参数精度ns级,另外两个都是ms级
      • 事件类型比较少:readsetwritesetexceptset,分别对应读、写、异常条件的描述符集合
      • select 的描述符类型使用数组实现,FD_SETSIZE 大小默认为 1024,因此默认只能监听 1024 个描述符
    • poll
      • 事件类型比较多【但也有数量限制】
      • 事件描述符使用链表连接起来,没有数量的限制
    • select poll 速度都比较慢(轮询方式找到IO完成的时间描述符)
      • select poll 每次调用都需要将全部描述符从应用进程缓冲区复制到内核缓冲区。
      • select poll 的返回结果中没有声明哪些描述符已经准备好,所以如果返回值大于 0 时,应用进程都需要使用轮询的方式来找到 I/O 完成的描述符。
    • epoll【向内核注册新描述符+回调函数+链表存储已准备好的IO描述符】
      • epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用  epoll_wait() 便可以得到事件完成的描述符。
      • 从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获得事件完成的描述符。
 
 
7.Java的NIO模型(reactor模型,单线程selector轮询)
  • selector:单个线程去监听多个channel(只是在准备好的时候调用,阻塞一下线程)
[]Java的NIO的selector会产生selectorProvider,会根据底层的操作系统生成不同的selector
 
 
 
8.AIO(回调机制实现,且不需要单独的线程来进行监听)
  • AIO的实现方式:
 
9.区别:
 
 

 

 
 
 

 

posted @ 2020-09-03 17:55  king断雨  阅读(298)  评论(0)    收藏  举报