一直以来对同步,异步,阻塞,非阻塞半懂不懂,下午搜了下网上别人的博客,稍微总结下,让自己也加深下理解。
首先,一般讲到同步,异步,阻塞,非阻塞都是涉及到IO,由于不同人在不同环境下对同步,异步IO理解不同,本文限定本文所讲述的IO均是Linux环境下的网络IO。
基本概念:
在讲述之前,先介绍几个概念。
--用户空间和内核空间
--进程切换
--进程阻塞
--缓存IO
用户空间和内核空间
现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。
进程切换
通常系统同时运行多个进程,为了控制进程的执行,内核必须有能力挂起某个正在运行的进程,也可以唤醒某个以前挂起的进程,这称为进程切换。
进程阻塞
正在运行的进程,由于在等待某件事情发生,在新的事情发生之前没有别的事情可以做,比如等待某数据到来,数据到来之前没什么事情做。此时,它高风亮节,自己自动让出CPU,从运行状态编程阻塞状态,可见,进程阻塞是自己自身的一种主动行为。也只有处于运行态的进程(获得CPU),才能处于阻塞状态。再次强调,处于阻塞态的进程,是不占用CPU资源的。这很重要也很有优势。所以目前网络编程各种套接字都是阻塞IO。
缓存IO
系统中,数据从进程写入磁盘,或者从磁盘读取数据,都不是直接与磁盘进行交互(那样速度太慢了),一般都有一个内核缓存区,用于缓存内容。一般地write将数据写入内核缓存区,就算写入完成。后续在自动flush进磁盘或者别的进程。
五种IO
进行一次IO访问(以read)为例,数据先被读到内核缓存区(例如这数据有可能来自网络,内核从网络层套接字一点点获取,或者有可能来自磁盘,内核从磁盘读取),然后从内核缓存区读取到用户进程中。因此,当调用read操作,执行两种操作如下:
1.等待内核中数据准备好
2,数据从内核缓存区中读到进程中来。
下面介绍5中IO,其主要来源于UNIX网络编程卷一第六章第二节。
阻塞IO //进程处于阻塞模式,让出CPU,自己进入休眠状态
Linux默认情况下所有的socket都是阻塞IO。
从上图可以看出,在进程调用recvfrom()函数时,首先看看内核中数据有没有准备好。如果没有,那么进程就阻塞在这。也就是说对于该进程来说,程序不再往下执行了,此时进程它会自动让出CPU,让CPU执行其它的内容。等到内核中的数据准备好了时,内核唤醒进程,再次占用CPU资源,进程收到内核缓冲区中的数据返回。
非阻塞IO //使用并不普遍,占用大量的CPU资源
非阻塞的方式下,进程并不让出CPU资源,进程它会一遍遍地问内核,你有没有准备好数据(这非常浪费CPU资源)。如果内核数据并没准备好,它都会立刻返回一个EWOULDBLOCK(对于阻塞模式下,该函数并不会返回),这算一个error信号。从用户的角度来看,他会立马得到一个结果,它就知道内核数据还没有准备好。你可以再次调用该函数(如放在一个循环中),一直调用,直到有数据返回。还有阻塞和非阻塞IO都属于同步IO,因为在内核准备好数据后,recvfrom从内核中将数据拷贝出来这部分过程仍然是block的,所以仍然是同步IO。
IO多路复用 //针对批量IP用户操作,效果很好
就是我们平时常见的 select,poll和epoll之类的,
这张图很类似于阻塞IO那张图,不同的是等待内核有数据的过程由select来做。考虑对于一个进程来说 ,它可能要监控好多个文件描述符的状态,此刻它的作用明显,它可以同时监控多个文件描述符,哪一个好了选择哪一个recvfrom().
信号驱动IO模型
很少用,不讲了。
异步IO模型
当我们处于异步IO模式下,当用户想要进行IO操作,只需告诉内核要进行IO操作,然后内核立刻返回。具体的IO操作和数据拷贝由内核完成。程序继续往下执行。当内核完成数据拷贝,内核通知进程。
同步IO 异步IO
同步IO:导致请求进程阻塞,直到IO操作完成。上面提到的前四种都属于同步IO。它们分别是阻塞IO,非阻塞IO,IO多路复用和信号驱动式IO模型。
异步IO:不导致请求进程阻塞。
最后给个5中IO模型的比较。
本文参考博客
https://segmentfault.com/a/1190000003063859和
http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520112163171778/,感谢原作者。
另参考UNIX网络编程卷一第六章第二节。