异步编程-阻塞&非阻塞
基础概念
异步是必须系统提供并行或者并发的能力
才能做到的,没有并行或者并发的系统不支持异步编程
所谓同步和异步,本质上区别是:逻辑请求发出后,是否需要等待结果,才能继续执行操作
并行
是多个逻辑结构的编程设计模式,异步实现的依赖
多任务在同一个时刻同时
执行,必须要求多个执行主体,比如多核CPU或者多CPU,每个核心独立执行一个任务,多个任务同时执行,不需要切换
并行
一定是同时运行
,系统提供的能力才能使用并行
并发
是多个逻辑结构的编程设计模式,异步实现的依赖
多个任务在同一个时间段内同时
执行,有资源就按调度执行,中间会进行切换,切换方式可以是抢占,也可以是阈值控制等等
并发并不一定是要同时执行
,所以并行是并发的一个子集,并发强调的是系统具有处理多个任务的能力,但不一定要同时
同步
是逻辑调用方式
,程序函数期望的描述
所谓同步,就是发出一个功能调用时,在没有得到结果之前,该调用就不返回或继续执行后续操作。简单来说,同步就是必须一件一件事做,等前一件做完了才能做下一件事
异步
是逻辑调用方式
,程序函数期望的描述
异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。当这个调用完成后,一般通过状态、通知和回调来通知调用者
对于异步调用,调用的返回并不受调用者控制
阻塞
是逻辑调用结果
,程序函数调用后的状态描述
阻塞调用是指调用结果返回之前,当前 进程/线程 会被挂起
,调用 进程/线程 只有在得到结果之后才会返回,并被唤醒
非阻塞
是逻辑调用结果
,程序函数调用后的状态描述
调用立刻返回,不会导致挂起
这里的立刻返回,其实程序本身还是可能被唤醒的,只是间隔很短,可以忽略
执行效果比较
根据上面的概念,可以组合 4 种异步编程情况
同步阻塞
直接入口 main 函数无脑访问阻塞函数即可
当阻塞时,当前程序会释放 cpu 和 资源,让相关的程序去执行
绝大多数程序的入口都是这种写法,一个 main 函数 阻塞循环,既让程序存活,也不占用必要的资源
同步非阻塞
例如 C++ Rust 默认多线程 开发就这个模型
linux 的 epoll 这种 IO 多路复用,也是经典的同步调用,非阻塞的
这种模型,需要调用者 轮询去查看调用结果,总体资源占用不大,调整轮询间隔,甚至可以达到性能和资源占用的微妙的平衡
异步阻塞
异步阻塞的目的就是更高的性能,更低延迟
能够让长耗时的任务安排到独立 进程/线程运行,达到更好的性能
不过现代计算机体系,异步支持得非常好了,使用 并发或者 并行,都能高效利用资源
比如 游戏 gameplay 主逻辑 就这么这么实现的
带有 GC 的编程语言,合理使用异步阻塞,可以指标上降低 GC ,原理是降低内存的创建和销毁,强行占用CPU来提高性能表现,稍微提高的 CPU 占用了反而是好处
异步非阻塞
通过调用 异步函数,埋一个回调函数,来接收异步函数的实际处理结果
其实这种方式是理论上最吃资源的,稍微思考一下就知道,都不等着不释放资源,肯定忙啊
这也同时是最优压榨系统资源的方式