IO模型
Linux系统IO分为内核准备数据和将数据从内核拷贝到用户空间两个阶段。
这张图大致描述了数据从外部磁盘向运行中程序的内存中移动的过程。
操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核,保证内核的安全,操作系统将虚拟空间划分为两个部分,一个部分为内核空间,一部分为用户空间。
网络IO的本质就是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作。对于一次IO访问(以read为例),数据会先被拷贝到操作系统内核的缓冲区,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间中。所以说,当一个read操作发生时,它会经历两个阶段:
第一个阶段:等待数据准备
第二个阶段:将数据从内核拷贝到进程中
对于socket流而言:
第一步:通常涉及等待网络上的数据分组到达,然后复制到内核的某个缓冲区。
第二步:把数据从内核缓冲区复制到应用进程缓冲区。
当然,如果内核空间的缓冲区中已经有数据了,那么就可以省略第一步。至于为什么不能直接让磁盘控制器把数据送到应用程序的地址空间中呢?最简单的一个原因就是应用程序不能直接操作底层硬件。
网络应用需要处理的无非就是两大类问题,网络IO,数据计算。相对于后者,网络IO的延迟,给应用带来的性能瓶颈大于后者。
——————————————————————————————
参考:http://www.cnblogs.com/dongguacai/p/5770287.html
基本概念再认识
同步:
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事。
例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回
异步:
异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。
例如 ajax请求(异步): 请求通过事件触发->服务器处理(这时浏览器仍然可以作其他事情)->处理完毕
阻塞:
阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回。
有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。 例如,我们在socket中调用recv函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。
非阻塞:
非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
——————————————————————————————————
参考:http://blog.youkuaiyun.com/jay900323/article/details/18141217/
五种IO模型
Linux的内核将所有外部设备都看作一个文件来操作,对一个文件的读写操作会调用内核提供的系统命令,返回一个file descriptor(fd,文件描述符)。而对一个socket的读写也会有相应的描述符,称为socketfd(socket描述符),描述符就是一个数字,它指向内核中的一个结构体(文件路径,数据区等一些属性)。
unix提供的5种IO模型:
阻塞IO模型
以套接字接口为例,在进程空间中调用recvfrom(用于从(已连接)套接口上接收数据,并捕获数据发送源的地址),其系统调用直到数据包到达且被复制到应用进程的缓存区种或者发生错误时才返回,在此期间一直会等待,进程在从调用recvfrom开始到它返回的整段时间内都是被阻塞的,因此被称为阻塞IO模型。
非阻塞IO模型
recvfrom从应用层到内核的时候,如果缓冲区没有数据的话,就直接返回一个错误,一般都对非阻塞IO模型进行轮询检查这个状态,看内核是不是有数据到来。
IO复用模型
linux系统提供select/poll,进程通过将一个或者多个fd传递给select/poll系统调用,阻塞在select操作上,这样select/poll可以帮助我们侦测多个fd是否处于就绪状态。select/poll顺序扫描fd是否就绪,但支持的fd数量有限,因此使用受到一些制约。Linux提供的epoll系统调用,采用基于事件驱动方式代替顺序扫描,因此性能更高,当有fd就绪时,立即回调函数rollback。
信号驱动IO模型
通过系统调用sigaction执行一个信号处理函数(此系统调用立即返回,进程继续工作,非阻塞),当数据准备就绪时,就为该进程生成一个SIGIO信号,通过信号回调通知应用程序调用recvfrom来读取数据。
异步IO模型
告知内核启动某个操作,并让内核在整个操作完成后(包括将数据从内核复制到用户自己的缓存区)通知我们。这种模型与信号驱动模型的主要区别是:信号驱动模型由内核通知我们何时可以开始一个IO操作,异步模型由内核通知我们IO操作何时已经完成。
_________________________________________
参考:《Netty权威指南》