Python学习之-- IO 操作

浪尽此生 提交于 2020-04-03 04:09:46

阻塞IO / 非阻塞IO /IO多路复用 / 异步IO

说明:同步IO包含(阻塞IO / 非阻塞IO /IO多路复用),因为他们有个共同特性就是都需要内核态到用户态的一个等待。

基本概念解释,环境限定为linux:

1:用户空间和内存空间

首先操作系统是采用虚拟存储器,就32位系统来说,它的虚拟存储空间是2的32次方==4G,操作系统的核心是内核,它是独立于普通的应用程序,它可以访问受保护的内存空间,底层硬件等,为保障用户进程不能直接操作内核,操作系统将虚拟存储空间分为2部分,分为:内核空间和用户空间,内核空间将最高的1G字节(寻址:0xC0000000到0xFFFFFFFF)分配使用,最低的3G字节分配给用户空间,供进程使用。

2:进程切换

也就类似线程切换,由内核将正在CPU上执行的进程挂起,然后恢复以前挂起的进程,这就是进程切换。所以进程都是在操作系统的内核的支持下运行的。与内核紧密相连
从一个进程切换到另一个进程,运行过程如下:
1:保存处理机上下文,包括程序计数器和寄存器
2:更新PCB信息
3:把进程的PCB移入相应的队列,
4:选择另一个进程执行,并更新其PCB
5:更新内存管理的数据结构
6:恢复处理机上下文

3:进程的阻塞

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

4:文件描述符

是一个用于表述指向文件的引用的抽象化概念。简单理解它就是一个索引值(非负整数),指向内核为每一个进程所维护的该进程打开的文件记录表

流程:程序打开一个文件或创建一个新文件,内核向进程返回一个文件描述符,通过文件描述符对文件句柄(就是真实文件对象)操作在程序设计底层基本是围绕文件描述符展开。这个概念只适用于unix,linux系统

5:缓存I/O

也被称为标准I/O,就是数据先被拷贝到操作系统的内核缓冲区,然后再从内核缓冲区拷贝到应用程序的地址空间。(就是说数据是从内核态到用户态的一个拷贝)
缺点:数据 在传输过程中需要在应用程序的地址空间和内核缓冲区中进行多次拷贝操作,这些拷贝操作对CPU和内存开销也是非常大。

I/O模式

I/O执行经历的2个阶段:
1:等待数据的准备,就是将数据先读到内核缓存中。
2:将数据从内核拷贝到进程中

通过这2个阶段,linux产生了5种网络模式:(阻塞I/0,非阻塞I/O,I/O多路复用,信号驱动I/O(这个用的少),异步I/O)

1:阻塞I/O (blocking IO)

在linux中,默认下所有的socket都是阻塞IO,
当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据(对于网络IO来说,很多时候数据在一开始还没有到达。比如,还没有收到一个完整的UDP包。
这个时候kernel就要等待足够的数据到来)。这个过程需要等待,也就是说数据被拷贝到操作系统内核的缓冲区中是需要一个过程的。而在用户进程这边,整个进程会被阻塞(当然,是进程自己选择的阻塞)。
当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。
看图:

特点:blocking IO的特点就是在IO执行的两个阶段(内核等数据阶段和内核态到用户态考数据阶段)都被block了。

2:非阻塞I/O (nonblocking IO)

在linux中,可以设置socket为非阻塞IO,
当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。
看图:

特点:nonblocking IO的特点是用户进程需要不断的主动问kernel数据是否准备完毕。(这里数据从内核到用户还是存在阻塞)

3:IO多路复用 (IO multiplexing)
就是:select,poll,epoll,这3种方式也称作 事件驱动模型,selelct/epoll好处是单个process可以同时处理多个网络连接的IO,
基本原理:select,poll,epoll会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。
看图:

注意:单线程下 阻塞模式是不能够实现多路复用
特点:I/O 多路复用的特点是通过一种机制一个进程能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select()函数就可以返回。
当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。

4:异步IO (asynchronous IO) 实现全程无卡点

用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。
看图:

总结:
blocking和non-blocking的区别
调用blocking IO会一直block住对应的进程直到操作完成,而non-blocking IO在kernel还准备数据的情况下会立刻返回
synchronous IO和asynchronous IO的区别
synchronous IO做”IO operation”的时候会将process阻塞,所以(阻塞,非阻塞,多路复用)都属于同步IO

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!