网络IO中的同步/异步&阻塞/非阻塞
//上次面试时候被问了网络相关的东西,一问三不知真的是十分的尴尬赶快补点知识。借鉴了网上很多博客,图片也来自网络。
一、同步/异步&阻塞/非阻塞
网络编程中同步、异步、阻塞、非阻塞的概念经常被提及,先说一下这些概念的含义:
同步——在进行调用时,如果没有得到调用结果,就不返回。
异步——在进行调用时,不需要立即得到调用结果,当其他部件完成调用结果后,通知调用者获取结果。
阻塞——在进行调用时,如果得不到调用结果,当前线程会被挂起,进入阻塞状态,也就是不再继续执行,直到得到结果才返回。
非阻塞——在进行调用时,如果得不到结果,线程不会阻塞,直接返回结果。
二、IO以及上述过程具体的区别
一次IO操作的过程是这样的:应用程序触发IO操作,进行系统调用——内核等待数据可读——内核完成IO(将数据从内核拷贝到进程中)——通知应用程序IO完成。对IO而言可以这样理解:
同步和异步是针对应用程序与内核交互而言的。同步IO操作得不到结果就会等待或者轮询去查看IO操作是否完成,直到得到数据才会返回;异步IO操作向内核提交IO请求,然后直接返回,做自己的事情,内核完成IO后再通知进程。二者的区别其实也是阻塞。
阻塞和非阻塞是针对调用得不到结果后的反应而言的。阻塞调用不返回,阻塞线程并等待结果;非阻塞调用立即返回,通知应用程序调用没有的到结果。可以理解为函数实现过程中两种不同的设计。
同步和阻塞都会等待结果,但实际上是有些不同的,阻塞调用会把线程阻塞,但同步调用在等待结果时当前线程还是激活的,只是逻辑上没有当前执行的函数。
三、IO模型
Linux下一共有五种IO模型,分别是:
1)阻塞I/O(blocking I/O)
2)非阻塞I/O (nonblocking I/O)
3) I/O复用(select 和poll) (I/O multiplexing)
4)信号驱动I/O (signal driven I/O (SIGIO))
5)异步I/O (asynchronous I/O (the POSIX aio_functions))
阻塞IO
用户进程调用了recvfrom这个系统调用,内核就开始准备数据,在网络中,这是数据并没有到达,内核就要等待数据,这段过程中,进程被阻塞。当内核获得足够的数据,将数据拷贝到用户内存,就可以给用户进程返回结果,然后用户进程解除阻塞状态,继续运行。阻塞IO可以理解为进程发起IO并等待直到准备好数据。
非阻塞IO
用户进程进行IO调用时,内核没有准备好数据,这时进程不会阻塞,而是返回一个error,表示没有得到调用的数据。用户进程得到了error的结果,知道数据还没有准备好,就可以进行其他的操作,过段时间再进行系统调用。一旦内核准备好了数据又收到应用程序的IO调用,就将数据拷贝到用户内存,并给用户进程返回结果。非阻塞IO可以理解为进程不断询问内核是否准备好数据。
IO复用
IO复用主要是select和epoll,与阻塞IO类似,这些函数会使进程阻塞,但是能够对多个进程的IO操作进行阻塞,select和epoll会不断轮询所有IO端口,当有一个IO数据准备好,就会通知对应的进程。
信号驱动IO
IO操作进行两次调用,第一次进行关于信号的调用,期间进程可以继续执行,数据准备好之后再次调用,将数据拷贝到用户内存,期间进程阻塞。
异步IO
用户进程发起IO操作后会立即返回,可以做其他的事,而内核在得到IO请求后,会开始准备进程所需要的数据并将数据拷贝到用户内存,当这一切完成后,内核会给用户进程发送一个信号,通知进程数据已经准备好。异步IO本质上是进行一次IO调用,然后把IO交给内核,等着内核通知就行了。
所有IO模型对比
在这张图中就可以明显看到非阻塞IO和异步IO的区别了
本文出自shad0w_walker,转载时请注明出处及相应链接。
本文永久链接: https://www.sdwalker.com/archives/656.html