同步和异步
主要针对C端,即客户端
跟S端不是完全没有关系,同步/异步机制必须S端配合才能实现. 同步/异步是由c端自己控制, 但是S端是否阻塞/非阻塞, C端完全不需要关心.
线程在执行中如果遇到磁盘读写或网络通信(统称为I/O 操作),通常要耗费较长的时间,这时操作系统会剥夺这个线程的CPU 控制权,使其暂停执行,同时将资源让给其他的工作线程,这种线程调度方式称为 阻塞。当I/O 操作完毕时,操作系统将这个线程的阻塞状态解除,恢复其对CPU的控制权,令其继续执行。这种I/O 模式就是通常的同步式I/O(Synchronous I/O)或阻塞式I/O (Blocking I/O)
同步
所谓同步,就是在c端发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事;
异步
异步的概念和同步相对。当c端一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者;
例如 ajax请求(异步): 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
阻塞和非阻塞
主要针对S端,即服务端
相应地,异步式I/O (Asynchronous I/O)或非阻塞式I/O (Non-blocking I/O)则针对所有I/O 操作不采用阻塞的策略。当线程遇到I/O 操作时,不会以阻塞的方式等待I/O 操作的完成或数据的返回,而只是将I/O 请求发送给操作系统,继续执行下一条语句。当操作系统完成I/O 操作时,以事件的形式通知执行I/O 操作的线程,线程会在特定时候处理这个事件。为了处理异步I/O,线程必须有事件循环,不断地检查有没有未处理的事件,依次予以处理。阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程所使用的CPU 核心利用率永远是100%,I/O 以事件的方式通知。在阻塞模式下,多线程往往能提高系统吞吐量,因为一个线程阻塞时还有其他线程在工作,多线程可以让CPU 资源不被阻塞中的线程浪费。而在非阻塞模式下,线程不会被I/O 阻塞,永远在利用CPU。
阻塞
进程阻塞,此时不占用CPU资源
阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回
非阻塞
非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
还是等快递的例子:如果用忙轮询的方法,每隔5分钟到A楼一层(内核缓冲区)去看快递来了没有。如果没来,立即返回。而快递来了,就放在A楼一层,等你去取。
比较
对象的阻塞模式和阻塞函数调用
对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方式,我们可以通过一定的API去轮询状 态,在适当的时候调用阻塞函数,就可以避免阻塞。而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。
- 同步,就是C端调用一个功能,该功能没有结束前,c端一直等待结果;
- 异步,就是C端调用一个功能,不需要知道该功能结果,该功能有结果后通知C端即回调通知;
- 阻塞,就是调用S端,S端没有得到结果之前,不会返回;
- 非阻塞,就是调用S端,S端立即返回,通过select通知调用者;
同步和异步I/O
应用程序的调用是否立即返回!
阻塞和非阻塞I/O
数据访问的时候进程是否等待!
阻塞和同步
阻塞调用是当前线程挂起,而同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。 例如,我们在socket中调用recv函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。(比如到你某个时候到A楼一层(假如是内核缓冲区)取快递,但是你不知道快递什么时候过来,你又不能干别的事,只能死等着。但你可以睡觉(进程处于休眠状态),因为你知道快递把货送来时一定会给你打个电话(假定一定能叫醒你))
示例
- 同步阻塞:老王用水壶煮水,并且站在那里,不管水开没开,每隔一定时间看看水开了没;
- 同步非阻塞:老王用水壶煮水,不再傻傻的站在那里看水开,跑去寝室上网,但是还是会每隔一段时间过来看看水开了没有,水没有开就走人;
- 异步阻塞:老王用响水壶来煮水,站在那里,但是不会再每隔一段时间去看水开,而是等水开了,水壶会自动的通知他;
- 异步非阻塞:老王使用响水壶煮水,跑到客厅上网去,等着响水壶自己把水煮熟了以后通知他;