同步与异步 阻塞和非阻塞
-
同步与异步
同步与异步其实是指对CPU时间片的利用,主要是看请求发起方,对消息的获取是主动发起的还是被动通知的.
- 如果是主动发起的,一直在等待应答结果(同步阻塞),或者可以处理其他事情,但要不断轮询查看发起的请求是否有应答结果(同步非阻塞)
- 如果是由服务方通知的也就是请求方发出请求后,要么一直等待通知(异步阻塞),要么先去干自己的事情(异步非阻塞),当事情处理完成后,服务方会主动通知请求方,它的请求已经完成,这就是异步,异步通知的方式有状态改变,消息通知,或者回调函数来完成,大多数时候采用的都是回调函数
-
阻塞与非阻塞
阻塞与非阻塞通常是指的针对IO的操作,简单的说,就是我们调用了一个函数后,再等待这个函数返回结果之前,当前的线程是处于挂起状态,还是运行状态,如果是挂起状态,就意味着当前线程什么都不能干,就等着获取结果,这就是同步阻塞,如果仍然是运行状态,就意味着当前线程是可以继续处理其他任务的,就是非阻塞状态
进程和线程的区别
- 进程是系统进行资源分配和调度的一个独立单位,进程有独立的地址空间
- 线程 是进程的一个实体,是CPU调度和分配的基本单位,它是比进程更小的能独立运行的基本单位,
- 一个程序至少有一个进程,一个进程至少有一个线程
线程执行开销小,但不利于资源的管理和保护,而进程正相反
IO模型
在网络环境下,通俗的讲,将IO分为两步: 第一步是等待 ; 第二步是数据搬迁.
如果想提高IO效率,主要就是降低等待时间,因此发展出来了五种IO模型,分别是阻塞IO,非阻塞IO,多路复用IO,信号驱动IO,异步IO
其中前四种都是同步IO,只有最后一种才是异步IO
-
阻塞IO
用户进程向系统内核发送请求后,在等待系统内核处理数据的这段时间,线程处于挂起状态,这时当前线程什么都不能干,就等待结果.当数据准备好了后,系统内核,将数据拷贝到用户内存,然后返回结果,用户进程才解决阻塞状态,重新运行起来
特点 | 在IO执行的两个阶段(等待数据和拷贝数据)都被阻塞 |
---|---|
典型应用 | 阻塞Socket, Java BIO |
优点 | 进程阻塞挂起不消耗CPU资源,及时响应每个操作. 实现难度低,开发应用较容易,适合并发小的网络应用 |
缺点 | 不适合并发量大的应用,因为一个请求IO会阻塞进程 需要为每一个请求分配一个处理进程(线程)以及时间响应,系统开销大 |
-
非阻塞IO
当用户进程发出请求后,如果内核中的数据还没准备好,那么他不会阻塞用户进程,而是立刻返回一个error,当用户进程判断结果是一个error时,他就知道数据还没准备好,于是它可以再次发送请求 ,就这样不停的轮询直到内核数据准备好了,并且再次收到了用户进程的请求,那么就会把数据拷贝到用户内存,然后返回
在等待系统内核处理数据的时候,非阻塞IO会不停的轮询查看发起的请求是否有应答结果,但可以去处理其他事情
特点 | 用户进程需要不断的主动询问内核(Kernel)数据准备好了没 |
---|---|
典型应用 | Socket设置NON_BlOCK |
优点 | 实现难度低,开发应用相对阻塞IO模型较难 |
缺点 | 进程轮询(重复)调用,消耗CPU的资源 适合并发量较小且不需要及时响应的网络应用开发 |
-
多路复用IO模型
多个进程的IO可以注册到一个复用器(Selector)上,当用户进程调用该Selector,Selector会监听注册进来的所有IO,如果Selector监听所有的IO,在内核上缓冲区上都没有可读的数据时,select调用就会返回,而后select调用进程可以自己或者通知注册到Selector上面的IO再次发起读取IO,读取内核中准备好的数据,多个进程注册IO后,只有一个select调用进程被阻塞
特点 | 对于每一个Socket,一般都设置成非阻塞,但是整个用户的进程其实一直都是被阻塞的,只不过进程是被select函数阻塞,而不是被SocketIO阻塞 |
---|---|
典型引用 | Java NIO , Nginx, |
优点 | 专一进程解决多个进程IO的阻塞问题,性能好,Reactor模式 适合高并发服务应用开发,一个进程/线程响应多个请求 |
缺点 | 实现和开发应用难度较大 |
-
信号驱动IO
用户进程预先告知内核,向内核注册一个信号处理函数,然后用户进程返回不阻塞,当内核数据就绪时会发送一个信号给进程,用户进程便在信号处理函数中调用IO读取数据
特点 | 并不符合异步IO的要求,只能算是伪异步,并且在实际中并不常用 |
---|---|
典型应用 | 应用场景较少 |
优点 | 应用场景少,不做总结 |
缺点 | 实现和开发应用难度大 |
-
异步IO
用户进程发起aio_read操作后,给内核传递与read相同的描述符,缓冲区指针,缓冲区大小三个参数及文件偏移,告诉内核整个操作完成时如何通知,用户进程立刻就可以开始做其他的事情,从内核上看,当它收到一个aio_read之后,就会立刻返回,不会对用户进程造成阻塞,内核会等数据准备完成后,然后将数据拷贝到用户内存上,当这一切都完成之后,内核会给用户进程发送一个信号,告诉它aio_read操作完成
特点 | 真正实现了异步IO,是五种IO模型中唯一的异步模型 |
---|---|
典型应用 | Java7 AIO ,高性能服务器应用 |
优点 | 不阻塞,数据一步到位,采用Proactor模式,非常适合高性能,高并发应用 |
缺点 | 需要操作系统的底层支持,Linux2.5内核首现,Linux2.6产品的内核标准特性,实现和开发应用难度大 |