I/O模型

转载自https://www.cnblogs.com/xiaoxi/p/6525396.html

I/O操作

1.查看数据是否准备就绪

2.拷贝数据(将数据从内核拷贝到用户线程)

 

阻塞I/O、非阻塞I/O

阻塞I/O:某个事件或任务执行过程中,发出一个请求操作,如果该操作的条件不满足,则会一直等待,直到条件满足。

非阻塞I/O:某个事件或任务执行过程中,发出一个请求操作,如果该操作的条件不满足,则会返回一个标志信息告知条件不满足,不会一直等待。

阻塞I/O和非阻塞I/O的区别在于第一阶段,如果数据没有准备就绪,在查看数据是否就绪的过程中是一直等待,还是返回标志性信息。

 

同步I/O、异步I/O

同步I/O:当用户发出I/O请求操作,如果数据没有准备就绪,需要通过用户线程或内核不断去轮询数据是否准备就绪,当数据就绪时,再将数据从内核拷贝到用户线程。

异步I/O:只有I/O请求操作由用户线程发出,I/O操作的两个阶段都是由内核自动完成,然后发送通知告知用户线程IO操作已经完成。在异步IO中,不会对用户线程产生任何阻塞。

同步I/O、异步I/O的关键区别在于数据拷贝阶段是用户线程完成还是内核完成,所以异步必须有操作系统底层的支持。

 

阻塞I/O模型

当用户线程发出I/O请求之后,内核查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。

data = socket.read()

 

非阻塞IO模型

当用户线程发出I/O请求后,内核查看数据是否就绪,如果没有就返回标志信息,用户线程就知道数据没有准备就绪,可以再次发起I/O请求直到数据就绪,将数据由内核拷贝到用户线程,然后返回。

在非阻塞I/O模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞I/O不会交出CPU,而会一直占用CPU。

while True:
    data = socket.read()
    if data:
        break

 

多路I/O复用模型

在多路复用I/O模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的I/O读写操作。因为在多路复用I/O模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进

程,并且只有在真正有socket读写事件进行时,才会使用I/O资源,所以它大大减少了资源占用。

另外多路复用I/O为何比非阻塞IO模型的效率高是因为在非阻塞I/O中,不断地询问socket状态是通过用户线程去进行的,而在多路复用I/O中,轮询每个socket状态是内核在进行的,这个效率要比用户线程要高的多。

 

信号驱动I/O模型

在信号驱动I/O模型中,当用户线程发起一个I/O请求操作,会给对应的socket注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用IO读写操作来进行实际的I/O请求操作。

 

异步I/O模型

在异步I/O模型中,当用户线程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从内核的角度,当它收到一个asynchronous read之后,它会立刻返回,说明read请求已经成功发起了,因此不会对用户线程产生任何block。然后,内核会等待数据准备完成,

然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程发送一个信号,告诉它read操作完成了。也就说用户线程完全不需要知道实际的整个I/O操作是如何进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示I/O操作已经完成,可以直接去使

数据了。

在异步I/O模型中,I/O操作的两个阶段都不会阻塞用户线程,这两个阶段都是由内核自动完成,然后发送一个信号告知用户线程操作已完成。用户线程中不需要再次调用IO函数进行具体的读写。这点是和信号驱动模型有所不同的,在信号驱动模型中,当用户线程接收到信

号表示数据已经就绪,然后需要用户线程调用I/O函数进行实际的读写操作;而在异步I/O模型中,收到信号表示I/O操作已经完成,不需要再在用户线程中调用I/O函数进行实际的读写操作。

前面四种IO模型实际上都属于同步I/O,只有最后一种是真正的异步I/O,因为无论是多路复用I/O还是信号驱动模型,I/O操作的第2个阶段都会引起用户线程阻塞,也就是内核进行数据拷贝的过程都会让用户线程阻塞。

 

posted @ 2019-06-13 11:37  fifa大西瓜  阅读(104)  评论(0)    收藏  举报