在说I/O模型之前,我们先来说说同步,异步,阻塞,非阻塞这四种调用方式的概念:
同步:在发出一个功能调用时,在没有得到结果之前,该调用就不返回,通俗点就是必须一件一件的做事,等这件事做完了才能做下一件事;
异步:异步和同步正好相对,当一个异步过程调用发出后,调用者不能立即得到结果,当该异步调用完成后,通过状态,通知和回调来通知调用者。
阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态之下,cpu不会给线程分配时间片,即线程暂停运行),函数只有在得到结果之后才会返回。
非阻塞:指我们的调用在不能立即得到结果之前,该函数不会阻塞当前线程,而会立即返回。
上面这几种情况说的通俗点就是下面这几种情况:
同步:就是我调用一个功能,该功能没有结束前,我就什么也不干,死等结果;
异步:就是我调用一个功能,不需要知道该功能结果,该功能有结果后通知我(回调通知);
阻塞:就是调用一个功能,该功能没有得到结果或接受完数据之前,该功能不会返回;
非阻塞:就是调用一个功能,该功能立即返回,通过select通知调用者;
同步IO和异步IO的区别:数据拷贝的时候,进程是否阻塞;
阻塞IO和非阻塞IO的区别:应用程序的调用是否立即返回。
我们来总结一下:
同步就是当一个进程发起一个函数(任务)调用的时候,一直等待直到函数(任务)完成,而进程继续处于激活状态。而异步情况下是当一个进程发起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行,当函数返回的时候,通过状态,通知,事件等方式通知进程任务完成。阻塞是当请求不能满足的时候,就将进程挂起,而非阻塞不会阻塞当前进程,即阻塞与非阻塞针对的是进程或线程,而同步与异步针对的是功能函数。
有了上面的理解,我们再分别看看以下的五种I/O模型:
1.阻塞式I/O模型:进程会一直阻塞,直到数据拷贝完成。应用进程调用一个I/O函数,导致应用进程阻塞,等待数据准备好,如果数据没有准备好,则一直等待,直到数据准备好了,从内核拷贝到用户空间,I/O函数函数返回成功指示。
下面我们来看看阻塞式I/O模型图,在调用recvfrom函数时,发生在内核中等待数据和复制数据的过程:
当调用recvfrom函数时,系统首先检查是否有数据准备好,如果数据没有准备好,那么系统就处于等待状态,当数据准备好之后,将数据从系统缓冲区复制到用户空间,然后改函数返回。在套接字应用程序中,当调用recvfrom函数时,未必用户空间就已经存在数据,那么此时recvfrom函数就会处于等待状态。
2.非阻塞式I/O模型:非阻塞式I/O通过进程反复调用IO函数(多次系统调用,并马上返回),在数据拷贝的过程中,进程是阻塞的。我们把一个socket接口设置为非阻塞就是告诉内核,当所请求的O操作无法完成时,不要将进程睡眠,而是返回一个错误。这样,我们的IO函数将不断地测试数据是否已经准备好,如果没有准备好,继续测试,知道数据准备好为止。在不断地测试中,会占用CPU大量的时间。
我们来看看非阻塞式I/O模型图:
把socket设置为非阻塞模式,就是在通知内核:在调用socket API函数时,不要让线程睡眠,而是让函数立即返回,在返回时,该函数返回一个错误代码。如上图所示,一个非阻塞式套接字多次调用recvfrom函数时,前三次调用该函数时,内核内核数据还没有准备好,该函数立即返回EWOULDBLOCK错误代码。第四次调用recvfrom时,数据已经准备好,被复制到应用程序的缓冲区中,recvfrom函数返回成功指示,应用程序开始处理数据。
3.I/O复用模型:主要是select或poll,对一个端口两次调用,两次返回,比阻塞I/O并没有什么优越性,关键是能够实现同时对多个IO端口进行监听。I/O复用模型会用到select,poll,epoll函数,这几个函数也会使进程阻塞,但是和阻塞I/O不同的是这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。
我们来看看I/O复用模型图:
从上图可以看到,我们阻塞于select调用,等待数据宝套接字变为可读。当select返回套接字可读这一条件时,我们调用recvfrom把所读数据报复制到应用缓冲区域。
4.信号驱动式I/O模型:两次调用,两次返回。首先我们允许套接口进行信号驱动I/O,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。模型图如下:
5.异步I/O模型:数据拷贝的时候,进程无需阻塞。当一个异步调用过程发生后,调用者不能立刻得到结果,实际处理这个调用的部件在完成后,通过状态,通知和回调来通知调用者的输入输出操作。在这里我们调用aio_read函数给内核传递描述符,缓冲区指针,缓冲区大小和文件偏移,并告诉内核整个操作完成后,如何通知我们。该系统调用立即返回,而且在等待I/O完成期间,我们的进程不会被阻塞。当内核将数据拷贝到缓冲区后,在通知应用进程。下面是模型图:
我们来总结一下各种I/O模型的比较:
我们从下图的比较中可以看到,前四种模型的区别主要在意第一阶段,因为他们的第一阶段是一样的:在数据从内核复制到进程的应用缓冲区期间,进程阻塞于recvfrom调用。而异步I/O模型这两个阶段都要处理。
我们的前四种模型都属于同步I/O模型,而第五种模型属于异步I/O模型。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。