1.同步与异步
所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才有可能完成(当然我们可以根据事务回滚、数据恢复等使之成为一种可靠的任务序列:要成功都成功,要失败都失败,两个任务的状态保持一致);异步不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务不需要等待其完成,即可立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。我们可以用打电话和发短信来比喻同步与异步操作。
2.阻塞与非阻塞
阻塞与非阻塞主要是从CPU的消耗上来说的,阻塞就是CPU停下来等待一个慢的操作完成以后,CPU才接着完成其它的事。非阻塞就是在这个慢的操作执行时CPU去干其他别的事,等这个慢的操作完成时,CPU再接着完成后续的操作。虽然表面上看非阻塞的方式可明显提高CPU的利用率,但是也带来了另外一种后果,就是系统的线程切换增加。增加的CPU使用时间能不能补偿系统切换成本需要好好评估。
3.两种方式的组合
组合的方式有四种:分别是同步阻塞、同步非阻塞、异步阻塞、异步非阻塞。
-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
组合方式 | 性能分析
-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
同步阻塞 | 最常用的一种用法,使用也是最简单的,但是I/O性能一般很差,CPU大部分处于空闲状态
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 提升I/O性能的常用手段,就是讲I/O的阻塞改成非阻塞方式,尤其在网络I/O是长连接同时传输数据也不是很多的情况下,提升性能非常有效
同步非阻塞 | 这种方式通常能提升I/O性能,但是会增加CPU消耗,要考虑增加的I/O性能能不能补偿CPU的消耗,也就是系统的瓶颈实在I/O还是在CPU上。---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
异步阻塞 | 这种方式在分布式数据库中经常用到,例如,在一个分布式数据库中写一条记录,通常会有一份同步阻塞的记录,而还有两至三份备份记录
| 写到其它机器上,这些备份记录通常都采用异步阻塞的方式写I/O。
| 异步阻塞对网络I/O能够提升效率,尤其像上面这种同时写多份相同数据的情况。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
异步非阻塞 | 这种组合方式用起来比较复杂,只有在一些非常复杂的分布式,集群之间的消息同步机制一般采用这种I/O组合方式。
| 它适合同时要传多份相同的数据到集群中不同的机器,同时数据的传输量虽然不大但是却非常频繁,这种网络I/O用这个方式性能达到最高。
---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
举例:
同步阻塞IO
你去一个银行柜台存钱。首先,你会将存钱的单子填好,然后交给柜员。这里,你就好比是application,单子就是调用的 system call,柜员就是kernel。提交好单子后,你就坐在柜台前等,相当于开始进行等待。柜员办好以后会给你一个回执,表示办好了,这就是 response。然后你就可以拿着回执干其它的事了。注意,这个时候,如果你办完之后马上去查账,存的钱已经打到你的账户上了。后面你会发现, 这点很重要。
同步非阻塞IO这次不是去银行存钱,而是去银行汇款。同样的,你也需要填写汇款单然后交给柜员,柜员进行一 些简单的手续处理就能够给你回执。但是,你拿到回执并不意味着钱已经打到了对方的账上。事实上,一般汇款的周期大概是24个小时,如果你要以存钱的模式来 汇款的话,意味着你需要在银行等24个小时,这显然是不现实的。所以,同步非阻塞IO在实际生活中也是有它的意义的。
异步阻塞IO比如说一个银行柜台,现在有10个人想存钱。按照现在银行的做法,一个个排队。第一个人先填存款单,然后提交, 然后柜员处理,然后给回执,成功后再轮到下一个人。大家应该都在银行排过对,这样的流程是很痛苦的。如果按照异步阻塞的机制,10个人都填好存款单,然后 都提交给柜台,提交完之后所有的10个人就在银行大厅等待。这时候会专门有个人,他会了解存款单处理的情况,一旦有存款单处理完毕,他会将回执交给相应的 正在大厅等待的人,这个拿到回执的人就可以去干其他的事情了。而前面提到的这个专人,就对应于select函数。
异步非阻塞IO比如银行存钱。现在某银行新开通了一项存钱业务。用户之需要将存款单交给柜台,然后无需等待就可以离开了。柜台办好以后会给用户发送一条短信,告知交易成功。这样用户不需要在柜台前进行长时间的等待,同时,也能够得到确切的消息知道交易完成。
参考: 及 JavaWeb技术内幕一书