补充:
发现一个更好的解释例子:同步是一件事我们从头到尾跟随着完成,异步是别人完成我们只看结果。阻塞是完成一件事的过程中可能会遇到一些情况让我们等待(挂起),非阻塞就是发生这些情况时我们跨过。
比如我和小明并排跑步,这就是一个同步的过程,异步就是他跑他的,我只关心他跑完没。跑步的过程中假设小明鞋带开了,我可以阻塞等待他也可以非阻塞的继续跑。
同步异步 阻塞非阻塞
今天和小伙伴讨论了这个问题,网上的说法有很多种,我按照自己的思路总结一边。
一句话总结区别:
同步异步关注的是事件发生时你的行为。
阻塞非阻塞关注的是的等待事件的状态。
下面看具体的分析
同步异步
同步:
在事件发生前,你的状态是时刻关注此事件,等待此事件给你返回结果。
例子:
烧水,同步就是你时刻关注着它,一段时间后,烧水壶冒烟了,你看见了,你知道水已经烧好。
那么在这段时间内你需要一直看着它是否冒烟。
异步:
在事件发生前,你并不关心此事件,而是自己去忙自己的,事件完成会通知你。
例子:
水烧好时,烧水壶会发出鸣声,你听见了,说明水烧好了
那么在这段时间内你不需要一直看着它,听见声音说明水已烧好。声音就是通知机制。
阻塞非阻塞
阻塞:
阻塞是你等待事件时为挂起状态,此时你什么也不能干,只能在等待事件。
例子:
烧水时,你在烧水壶旁边仅仅等待水开,水开了自己立刻知道。
非阻塞:
非阻塞是等待事件,如果事件没发生,不挂起自己
例子:
烧水时,你过来看一眼,水没开,走了,过一会在过来看,没好,这样不断重复,直到水开为止。
同步异步阻塞非阻塞组合
网络IO其实简单分为以下步骤:
在网卡上等待数据–>从内核态拷贝到用户态(拷贝数据)
5种IO模型
同步阻塞:
在我们最开始学习网络编程一定写过同步阻塞IO模型,时刻关注着对方事件,如果对方没有消息则阻塞在read系统调用上。
如上图1部分,网络IO两个步骤一直在blocking。
同步非阻塞:
我们可以将套接字socket设置为非阻塞的,那么就会出现为上图第二种情况,不断的check直到事件发生,它在拷贝数据阶段依旧是阻塞的。没有数据来会阻塞在那里。
第三中情况,I/O multiplexing,select会阻塞在select函数,poll阻塞在poll函数,epoll阻塞在epoll_wait函数,他们第二阶段都是阻塞的。单独说下I/O multiplexing
网上很多人将epoll归为异步非阻塞的,我认为这是不对的,从概念上来讲,异步,从事件开始前我就不关注此事件了,你完成了告诉我,而epoll不是,如果没有数据它会阻塞在epoll_wait,我想可能有些人从epoll的优点来看感觉epoll的确是异步的,因为epoll_wait每次返回的是就绪的事件,让大家以为“我不用管了,它返回给我的就是就绪事件呀!”,其实是不对的,网络IO前面说了是分为两个步骤的,epoll_wait会阻塞在第二个步骤拷贝数据,那么它还是阻塞的,其中任何一个步骤阻塞都会阻塞。
异步非阻塞:
linux下应当是aio_*一套API了,但linux异步IO支持并不好,网上批评的文章很多。
可参考这篇文章
Linux kernel AIO这个奇葩
异步非阻塞说明我们完全不用关心事件执行过程,事件完成后发消息给我们,我们接受即可,不会阻塞在网卡上,不会阻塞在拷贝数据上。(注意:阻塞在拷贝数据上也是阻塞啊)。
异步阻塞
没听说过,个人认为也没有异步阻塞这一说,异步不可能阻塞,查了资料有人反对贴上了IBM的一篇文章
使用异步 I/O 大大提高应用程序的性能
看了一点觉得就有问题。
他异步阻塞I/O指的是epoll。
最后,上面仅仅是个人的一些看法和观点,我们学习还是要带着审视的眼光,需要有自己判断知识好坏的能力。
如果文章内容有问题,还请指出^_^