阻塞IO, 非阻塞IO, 同步IO,异步IO介绍

一、前言

 

  1、我们之前讲了IO操作什么时候切换回来呢?

  我们刚刚讲了回调函数,这个回调函数是当你的程序一遇到IO操作,再一切换,这个切换的时候,切换之前你等着IO操作完了再回来。

  2、IO 为什么不阻塞呐?

  因为IO操作是用操作系统完成的,咋们用户读一个文件,你以为自己的程序打开一个文件,然后去把文件的内容读出来。其实不然,是你的操作系统的调度接口打开这个文件,然后把这个数据读会开,其实是操作系统负责IO的控制。

  3、我怎么切换回来?

  加一个回调函数,就是我去切换之前,调操作系统IO接口的时候,告诉操作系统,说你处理完了之后,调一下这个回调函数,这个回调函数就会通知我,通知我了就代表执行完了,我就回来把这个IO拿到了,所以就是通过这个事件驱动的方式。出现这个IO操作,我就注册这个事件,就是IO事件交给操作系统,操作系统内部有一个队列,处理完了吧结果返回给你,通知回调函数通知你。

二、逻辑图

 

三、IO多路复用

 

3.1、概念说明

在进行解释之前,首先要说明几个概念:
- 用户空间和内核空间
- 进程切换
- 进程的阻塞
- 文件描述符
- 缓存 I/O

3.2、用户空间与内核空间

现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。

3.3、进程切换

为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换。因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。

从一个进程的运行转到另一个进程上运行,这个过程中经过下面这些变化:
1. 保存处理机上下文,包括程序计数器和其他寄存器。
2. 更新PCB信息。

3. 把进程的PCB移入相应的队列,如就绪、在某事件阻塞等队列。
4. 选择另一个进程执行,并更新其PCB。
5. 更新内存管理的数据结构。
6. 恢复处理机上下文。

总而言之就是很耗资源,具体的可以参考这篇文章:进程切换

注:进程控制块(Processing Control Block),是操作系统核心中一种数据结构,主要表示进程状态。其作用是使一个在多道程序环境下不能独立运行的程序(含数据),成为一个能独立运行的基本单位或与其它进程并发执行的进程。或者说,OS是根据PCB来对并发执行的进程进行控制和管理的。 PCB通常是系统内存占用区中的一个连续存区,它存放着操作系统用于描述进程情况及控制进程运行所需的全部信息

3.4、进程阻塞

正在执行的进程,由于期待的某些事件未发生,如请求系统资源失败、等待某种操作的完成、新数据尚未到达或无新工作做等,则由系统自动执行阻塞原语(Block),使自己由运行状态变为阻塞状态。可见,进程的阻塞是进程自身的一种主动行为,也因此只有处于运行态的进程(获得CPU),才可能将其转为阻塞状态。当进程进入阻塞状态,是不占用CPU资源的

3.5、文件描述符fd

文件描述符(File descriptor)是计算机科学中的一个术语,是一个用于表述指向文件的引用的抽象化概念。

文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。

3.6、缓存I/O

缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O 操作都是缓存 I/O。在 Linux 的缓存 I/O 机制中,操作系统会将 I/O 的数据缓存在文件系统的页缓存( page cache )中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间

缓存 I/O 的缺点:
数据在传输过程中需要在应用程序地址空间和内核进行多次数据拷贝操作,这些数据拷贝操作所带来的 CPU 以及内存开销是非常大的。

四、总结

 4.1、前面总结

  1、操作系统本身运行也需要内存空间,所以你8G内存,往往使用,达不到8G。

  2、只有内核是操作系统本身访问的,其他的程序是不能直接访问内核的,只有通过操作系统访问。

4.2、socket好几次send都合在一块了,黏包了?

  为了减少从内核态到用户态的数据来回的copy,因为如果你打开一个文件,你读到内存里,你以为是直接读到你的用户的内存里面,其实是先读到缓存里面,也就是内核的缓存里面,然后再由内核帮你把这份数据copy到用户的内存里面。就是为了避免这里的来回copy,耗资源,这样的话效率就高。

4.3、别人发了一个数据,你是怎么接收到的?

  别人发来数据不是发到你用户的socket程序里面,而是先发到操作系统的IO接口里,然后操作系统IO接口,其实读到了内核空间里面,再把这份数据copy到你的用户的内存空间里面的,数据要从内核态copy到用户态。这里面是cpu调copy这个接口需要消耗cpu,最主要的是内存的开销。都是在内存中的,只是有一个内核空间和用户空间,数据需要从内核把这个数据转给你。

 

posted @ 2017-10-26 17:43  人生是一场修行  阅读(103)  评论(0编辑  收藏  举报