Linux系统编程——深度理解5种IO模型

Posted 努力学习的少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux系统编程——深度理解5种IO模型相关的知识,希望对你有一定的参考价值。

目录

一.IO基础知识

1.直接IO与非直接IO

2.什么是DMA技术?

二.五种模型的IO

1.阻塞IO

2. 非阻塞IO

3.IO多路转接

4.信号驱动IO

5.异步IO


一.IO基础知识

1.直接IO与非直接IO

磁盘IO是十分缓慢的,所以Linux为了减少磁盘IO,在系统调用后,会利用DMA技术先将磁盘中的数据拷贝到内核的缓冲区中,这个缓存就是页缓存,只有当缓存满足某些条件时,才会发起磁盘IO。

根据是 是否使用内核缓存 来区分是 直接IO 还是 非直接IO

  • 直接IO,不会发生内核缓存和用户层面的数据拷贝,而是直接经过文件系统直接访问磁盘。
  • 非直接IO,读操作时,数据从内核中拷贝给应用进程,写操作时,数据从应用进程拷贝给内核空间,内核空间再决定什么时候写入到磁盘当中。

 同样的,  socket通信也是需要在内核当中建立缓冲区来让两台主机的进程之间的通信。

2.什么是DMA技术?

DMA传输将数据从一个地址空间拷贝到另一个地址空间无需cpu的干涉,提供在 外设存储器,或者 存储器 存储器 之间的高速缓存数据传输。

DMA技术就是基于以上的设想设计的,它的作用是解决了大量数据转移过度消耗cpu资源的问题,有了DMA技术能够cpu去做更为复杂的任务

二.五种模型的IO

1.阻塞IO

  • 用户程序调用read,线程会被阻塞住,它需要等待底层的DMA技术将数据拷贝到内核当中
  • 此时的线程什么都不会做,直到数据准备好了,并把数据从内核缓冲区拷贝到用户缓冲区中。
  • 当拷贝完成时,read才会返回.

2. 非阻塞IO

  • 如果内核中的数据没有准备好,则会立刻返回,并且返回EWOULDBLOCK错误码,虽然read立刻返回,但底层的DMA技术会一直的将数据拷贝到内核当中,
  • 如果内核中的数据准备好,内核将数据拷贝到应用进程当中。
  • 非阻塞IO一般都需要设置为循环轮询,即不断的区内核中查看数据是否就绪,在这个过程中,应用进程什么都做不了,这对cpu是较大的浪费

3.IO多路转接

IO多路转接是什么?

IO多路转接它能够同时等待多个文件描述符并且能够同时让多个文件描述符利用DMA技术将数据拷贝到内核种,如果有某个文件描述符中有事件发生(读事件或写事件),则会保存相对应的文件描述符,并最后返回給应用进程。

为什么会有IO多路转接?

在阻塞IO和非阻塞IO的例子当中,它们只是让一个线程去等待一个文件描述符的情景但是一个应用进程它很有可能会进行多种IO数据交互,例如 一个线程中可能会与磁盘上的多个文件进行数据IO交互,也可能会有多个socket进行网络通信,所以一个线程可能在不断的进行IO数据交互和数据处理不断徘徊,为了提高一个进程的处理事件的效率,我们需要提高IO效率和数据处理的效率,今天,我们先考虑如何提高进程的IO效率。而IO多路转接本质就是提高进程IO的效率它主要是减少IO阻塞的时间和系统调用的次数。如下:

假设一个进程需要对文件描述符fd为1~32的IO数据交换,模拟一下 阻塞IO非阻塞IO ,IO多路转接 进行IO数据交换的过程。

阻塞IO进行多个文件描述等待:

  • 每次只能一个等待文件描述符,当调用read去读取fd=1的数据,线程就会阻塞住,DMA技术将数据从磁盘上拷贝到内核上,直到内核把数据准备好。
  • 将数据拷贝到应用进程,返回给应用进程。
  • 应用进程再处理完数据,接下来再调用read区读取fd=2的数据,如此循环。
  • 阻塞IO每次调用read都会阻塞一段时间,这显然IO效率是十分低下的。

非阻塞IO进行多个文件描述符等待:

  • 当某个文件描述符的数据没有准备好时,则会立刻返回,然后再进行扫描下一个文件描述符。
  • 当文件描述符有数据,内核才将数据进行拷贝到应用进程,应用进程才会处理数据。
  • 这显然比阻塞IO的效率要高,因为它不回被阻塞再内核里面。
  • 但是非阻塞IO会频繁调用read,即使数据没有准备好,这对cpu也会有一定的消耗。

IO多路复用等待多个文件描述符:

  • IO多路复用的功能是让内核扫描一遍所有的文件描述符fd扫描到文件描述符则会调用DMA技术,将数据拷贝到内核中,如果某个文件缓存区有数据了,则将其文件描述符存储起来,如果没有数据,则直接跳到下一个文件描述符。
  • 扫描一遍后,将所有数据准备好的文件描述符返回给应用进程,应用进程就会知道哪些文件描述符已经将数据准备好了。
  • 应用进程拿到这些fd后,就可以依次调用read进入内核,且不会被阻塞,因为进入文件描述符的数据缓冲区的数据一定是准备好的,所以无需等待
  • IO多路转接能够同时让多个文件描述符利用DMA技术将数据拷贝到内核中,减少应用进程阻塞的时间。

  •  阻塞IO每次读取数据都需要阻塞一段时间,这段时间它不能去等待其他的的文件描述符,因此IO效率是比较低的。
  • 非阻塞IO去读取数据,如果没有数据,则它会里可以返回,可以去读取其他文件描述符的数据,但是它会频繁的调用read接口即使对应的文件缓存区没有数据这也对cpu有一定的消耗
  • 多路转接它能够同时等待多个文件描述符,扫描到的文件描述符,则会进行DMA技术对数据进行拷贝,如果某个文件描述符对应的缓冲区有数据,则会将它保存下来,如果没有数据,则跳过查看下一个文件描述符,扫描到最后,则返回所有数据就绪的文件描述符给应用进程,当应用进程调用read去文件缓存区中,因此IO多路转接它能够减少阻塞的时间,且可以减少read的系统调用来提高进程的IO效率

4.信号驱动IO

  • 应用进程设置一个信号,立刻返回,则底层利用DMA技术将数据拷贝内核缓存区上.
  • 当内核数据准备好的时候,内核就利用信号会通知应用进程,让应用进程主动发起read将内核数据拷贝到应用进程当中。

5.异步IO

信号驱动IO, 阻塞IO,非阻塞IO, 多路转接,它们都属于 同步IO,这里的同步是属于数据拷贝过程的同步,他们都会主动去调用read将数据从内核拷贝到应用进程上,在内核在拷贝数据到应用进程 这个过程中 ,应用进程是被阻塞住的,他们不会做任何事情

真正的异步IO是,内核准备数据和数据拷贝到应用进程过程中 应用进程是不会等待,当数据就绪时,内核会主动将数据拷贝到应用进程当中,拷贝完成后,内核才会通知应用进程


 

以上是关于Linux系统编程——深度理解5种IO模型的主要内容,如果未能解决你的问题,请参考以下文章

Java NIO Reactor网络编程模型的深度理解

深度长文:从bio到nio到aio,再到响应式编程

从操作系统层面理解Linux下的网络IO模型

5种IO模型阻塞IO和非阻塞IO同步IO和异步IO

网络编程进阶:并发编程之协程IO模型

Linux五种IO模型