I/O 模型

来源:互联网 发布:图书管理系统c语言链表 编辑:程序博客网 时间:2024/06/05 03:40

预备知识1: 用户空间和内核空间

  • 虚拟存储器
    • 以32位操作系统为例, 能访问的内存最大为4G
      这里写图片描述
  • 0–3G 虚拟地址分配给各个用户进程(用户空间)
    • 每个进程都有3G的虚拟地址空间
  • 3–4G 虚拟地址分配给操作系统核心和驱动程序(内核空间)
  • 用户空间和内核空间不能用指针来传递数据()

注意:
- Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中。用户空间的内存映射采用段页式,而内核空间有自己的规则。
- 32位系统用户进程最大可以访问3GB,内核代码可以访问所有物理内存。
- 64位系统用户进程最大可以访问超过512GB,内核代码可以访问所有物理内存。
- 用户态的程序就不能随意操作内核地址空间里的数据,具有一定的安全保护作用;于此同时,在实时性方面稍微有所牺牲。也要就是说,只要内核代码没有问题,用户空间程序的错误和BUG一般来说不会导致系统崩溃,提高了系统的健壮性

这里写图片描述

内核态与用户态:
(1)当一个任务(进程)执行系统调用而陷入内核代码中执行时,称进程处于内核运行态(内核态)。比如进行文件访问

(2)当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。

预备知识2: I/O模式

  • 缓存I/O

    • 数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。
  • 进程读取数据的两个阶段

    • 等待内核数据准备
    • 将数据从内核拷贝到进程中

假设我们有个进程,建立了一个socket , 从服务器读取数据, 那数据从网络到达时, 先被读取到内核的缓冲区, 然后再复制到进程的缓冲区

预备知识3: 进程状态和阻塞

这里写图片描述

什么时候会阻塞? 进程正在运行, 需要从硬盘, 网络等地方读取数据, 由于IO操作很慢, 进程会被放到阻塞队列中等待。

IO模型

由于数据的读取分为两个阶段,所以IO读取分为若干种模式下面的图是从《Unix网络编程》书中截取出来的图片,我认为这几张图很好的解释了这几种IO模型的特点。

同步阻塞型IO

这里写图片描述

最常用的I/O模型就是阻塞I/O,缺省的情况下所有文件的操作都是阻塞的。以模型Socket为例, 进程被阻塞, 直到数据从内核空间复制到用户空间,在此期间一直会等待。

注意 Socket与数据报(UDP)的区别:前者概念更宽泛,包括后者再加上TCP

同步非阻塞型IO

这里写图片描述

当进程调用recvFrom的时候, 系统不把进程置为阻塞状态,相反,而是返回一个标志符。 这样进程就可以反复轮询内核,询问数据准备好了没有, 这样会耗费大量CPU时间。

异步IO

这里写图片描述

进程告知内核启动某个操作,并让内核完成以后通知进程。

IO复用模型

这里写图片描述

进程告诉内容: 我这里有100多个(假设)socket, 你帮我看看哪一个可以读了, 然后告诉我, 哪一个socket 好了, 我就会发起receiveFrom调用。本质上IO复用模型也是同步阻塞型IO,但是它与同步阻塞型IO的区别是它可以管理很多socket
应用场景:当需要同时处理多个客户端接入请求时,可以利用多线程或者I/O多路复用技术进行处理。I/O多路复用技术通过把多个I/O的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与传统的多线程/多进程模型相比较,I/O多路复用模型的最大优势是系统开销小,系统不需要创建新的额外进程或线程,也不需要维护这些进程和线程的运行。
- 服务器需要同时处理多个监听状态或者多个连接状态的套接字(Socket)

各种IO模型的对比

这里写图片描述

总结

  • 操作系统中的很多概念是关联的, 例如你理解了虚拟存储器, 才有可能理解用户空间,内核空间, 然后才能真正理解阻塞,非阻塞, 异步,同步
  • 将数据从内核复制到用户空间都是阻塞的,所谓非阻塞就是等待数据是非阻塞的
  • 程序(进程)阻塞后,CPU不会分配时间片给改程序运行。

问题:

  • 为什么异步IO不能完全取代阻塞IO?
    阻塞IO有存在的道理,你想一个业务场景下,必须要某一 步的IO操作完成才能进行后面的任务,后面的所有的操作都建立在这个IO完成上。在这种情况下你就得用阻塞IO 了 。
原创粉丝点击