非阻塞算法 vs 阻塞算法
阻塞和非阻塞是在并发编程中常见的两个名称,其具体含义是什么呢?
我们所说的 “阻塞”是指进程在发起了一个系统调用(System Call) 后, 由于该系统调用的操作不能立即完成,需要等待一段时间,于是内核将进程挂起为等待 (waiting)状态, 以确保它不会被调度执行, 占用 CPU 资源。
友情提示: 在任意时刻, 一个 CPU 核心上(processor)只可能运行一个进程 。
阻塞算法简单概括为:会阻塞线程,直到请求的操作可以被执行,如果不能执行就需要一直等待
例如,如果一个线程产生往一个已经满了的阻塞队列里插入一个元素,这个线程就会阻塞,直到其他线程从这个阻塞队列中取走了一些元素。
例如阻塞式发送:发送方进程会被一直阻塞,直到消息被接受方进程收到
阻塞式接收:接收方调用 receive() 后一直阻塞, 直到消息到达可用。
而非阻塞算法则是,进行该操作之后立刻可以去干其他事情!,不是一直被阻挡在那里。其中可能得到一个失败的消息,或者得到一个不完整不正确的结果,但是不影响自己做其他事情。
例如在满了的非阻塞队列里插入一个元素,会通知插入失败,不会一直等待别人取走元素。
例如非阻塞式发送(nonblocking send): 发送方进程调用 send() 后, 立即就可以其他操作。
非阻塞式接受(nonblocking receive):接收方调用 receive() 函数后, 要么得到一个有效的结果, 要么得到一个空值, 即不会被阻塞。
非阻塞算法的优点
1.选择
当请求不能被执行时候,使用非阻塞算法能够多了一种选择。可以选择继续等待,也可以选择返回给用户失败信息。
2.没有线程挂起
挂起和恢复一个线程的代价是昂贵的。没错,随着时间的推移,操作系统和线程库已经越来越高效,线程挂起和恢复的成本也不断降低。不过,线程的挂起和户对任然需要付出很高的代价。
无论什么时候,一个线程阻塞,就会被挂起。因此,引起了线程挂起和恢复过载。由于使用非阻塞算法线程不会被挂起,这种过载就不会发生。这就意味着CPU有可能花更多时间在执行实际的业务逻辑上而不是上下文切换。
在一个多个CPU的系统上,阻塞算法会对阻塞算法产生重要的影响。运行在CPUA上的一个线程阻塞等待运行在CPU B上的一个线程。这就降低了程序天生就具备的并行水平。当然,CPU A可以调度其他线程去运行,但是挂起和激活线程(上下文切换)的代价是昂贵的。需要挂起的线程越少越好。
与同步异步区别
同步和异步关注的是消息通信机制
同步:调用者主动等待这个调用的结果。
异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
总结来看:
阻塞非阻塞关注的是:程序调用是要一直办完这件事情还是可以立即可以做其他事情
同步异步关注的是:消息是怎么通信的,是一直询问还是被通知。