并行与并发
并行(parallellism)是指两个及以上个进程在同一时刻(时间点)同时执行。
并发(concurrency)指两个及以上个进程在同一时间间隔(时间段)内同时执行。
同步与异步
同步
-
网络与通信
同步(synchronous)是指多个有相互之间一定联系的并发执行的进程,通过一定的机制,使之有序执行,从而使其总的运行结果符合预期。
-
软件设计
一种计算机术语,一般指的是在两个或多个数据库、文件、模块、线程之间用来保持数据内容一致性的机制
异步
-
网络与通信
异步(asynchronous)是指多个有相互之间一定联系的并发执行的进程,执行时相互之间没有约定一定的次序。电子邮件和
AJAX就是一种异步通信方式 -
软件设计
按照这种设计编写的代码使得程序能够要求一个任务与先前的一个(或多个)任务一起执行,而无需为了等待它们完成而停止执行。当后来的任务完成时,程序将使用约定好的机制通知先前的任务,以便让它知道任务已经完成
阻塞与挂起
阻塞(block)是指当前进程因操作系统分配的时间片用完之外的、因某资源没有满足的原因不能继续运行,从而交出当前 CPU 的使用权而暂停的一种状态。而当之前缺少的该资源被满足之后,该进程将被解除阻塞而逐步恢复之前的运行状态。
挂起(suspend)是指当前进程发生了内存等共享资源的紧急不足,或者由于用户的意愿,现阶段不需要运行等原因,处于一种不接受操作系统调度的状态。阻塞与之的区别在于,当之前缺少的该资源被满足之后,处于阻塞状态的进程将自动被解除现在的暂停运行的状态,这个自动的过程是由操作系统设法完成的。但对于处于挂起状态的进程来说,当前暂停运行的状态不会自动被解除,除非用户主动对其进行激活。
阻塞
- 阻塞是指调用结果返回之前,当前线程会被挂起
- 调用线程只有在得到结果之后才会返回
非阻塞
非阻塞调用指在不能立刻得到结果,该调用不会阻塞当前线程
关系
- 适用于编程语言层面,但不适用于操作系统层面
- 这些概念跟是发送方还是接收方没有必然关系
- 主线程的角度上
- 获得期望资源之前的行为
同步阻塞
在需要某资源时马上发起请求,并暂停本线程之后的程序,直至获得所需的资源。
同步非阻塞
在需要某资源时马上发起请求,且可以马上得到答复,然后继续执行之后的程序。但如果得到的不是完整的资源,之后将周期性地的请求,直至获得所需的资源。
异步阻塞
在需要某资源时不马上发起请求,而安排一个以后的时间再发起请求。当到了那时发出请求时,将暂停本线程之后的程序,直至获得所需的资源。在获取资源之后,使用共享信号量、异步回调等方式将结果异步反馈。
异步非阻塞
在需要某资源时不马上发起请求,而安排一个以后的时间再发起请求。当到了那时发出请求时,可以马上得到答复,然后继续执行之后的程序。但如果得到的不是完整的资源,之后将周期性地的请求。在最终获取到资源之后,使用共享信号量、异步回调等方式将结果异步反馈
异步阻塞和同步阻塞
- 从运筹学的角度来说,合理的安排任务的执行时机是可以提高效率的
- 异步与同步不同,异步是声明式编程、响应式编程、函数式编程、面向方面编程的必要技术。和命令式编程不同,异步编程更优雅、可读性更强。尤其是对框架化的编程来说,异步编程可以让开发人员忽略不重要的细节,大大提高开发效率。如果异步函数是以闭包的形式提供的,还具有闭包自带的强大功能,比一般的同步函数在编程上要方便很多
- 不使用框架的代码,使用异步会让程序流程走向变得复杂
- 异步代码的调试难度通常远大于同步代码
IO 系统调用(操作系统层面)
IO 基本概念
IO (Input/Output,输入/输出)即数据的读取(接收)或写入(发送)操作,通常用户进程中的一个完整 IO 分为两阶段
- 用户进程空间 <--> 内核空间
- 内核空间 <--> 设备空间(磁盘、网络等)
IO 有内存 IO、网络 IO 和磁盘 IO 三种,通常我们说的 IO 指的是后两者
- 进程无法直接操作 I/O 设备,其必须通过系统调用请求内核来协助完成I/O动作
- 内核会为每个 I/O 设备维护一个缓冲区
对于一个输入操作来说,进程IO系统调用后,内核会先看缓冲区中有没有相应的缓存数据,没有的话再到设备中读取,因为设备IO一般速度较慢,需要等待;内核缓冲区有数据则直接复制到进程空间
一个网络输入操作通常包括两个不同阶段
- 等待网络数据到达网卡 → 读取到内核缓冲区,数据准备好
- 从内核缓冲区复制数据到进程空间
IO 模型
同步 IO 模型
阻塞 IO 模型
进程发起IO系统调用后,进程被阻塞,转到内核空间处理,整个IO处理完毕后返回进程。操作成功则进程获取到数据。
- 进程阻塞挂起不消耗CPU资源,及时响应每个操作
- 实现难度低、开发应用较容易
- 适用并发量小的网络应用开发
- 不适用并发量大的应用:因为一个请求IO会阻塞进程,所以,得为每请求分配一个处理进程(线程)以及时响应,系统开销大。
非阻塞 IO 模型
进程发起IO系统调用后,如果内核缓冲区没有数据,需要到IO设备中读取,进程返回一个错误而不会被阻塞;进程发起IO系统调用后,如果内核缓冲区有数据,内核就会把数据返回进程。
- 进程轮询(重复)调用,消耗CPU的资源;
- 实现难度低、开发应用相对阻塞IO模式较难;
- 适用并发量较小、且不需要及时响应的网络应用开发
IO 复用模型
多个的进程的IO可以注册到一个复用器(select)上,然后用一个进程调用该select, select会监听所有注册进来的IO; 如果select没有监听的IO在内核缓冲区都没有可读数据,select调用进程会被阻塞;而当任一IO在内核缓冲区中有可数据时,select调用就会返回; 而后select调用进程可以自己或通知另外的进程(注册进程)来再次发起读取IO,读取内核中准备好的数据。
Nginx 使用
- 专一进程解决多个进程IO的阻塞问题,性能好;Reactor模式;
- 实现、开发应用难度较大;
- 适用高并发服务应用开发:一个进程(线程)响应多个请求;
信号驱动的 IO 模型
当进程发起一个IO操作,会向内核注册一个信号处理函数,然后进程返回不阻塞;当内核数据就绪时会发送一个信号给进程,进程便在信号处理函数中调用IO读取数据。
- 回调机制
- 实现、开发应用难度大
异步 IO 模型
当进程发起一个IO操作,进程返回(不阻塞),但也不能返回果结;内核把整个IO处理完后,会通知进程结果。如果IO操作成功则进程直接获取到数据。
- 不阻塞,数据一步到位;Proactor模式;
- 需要操作系统的底层支持,LINUX 2.5 版本内核首现,2.6 版本产品的内核标准特性;
- 实现、开发应用难度大;
- 非常适合高性能高并发应用;
IO 模型比较
非阻塞 IO 系统调用 和 异步 IO 系统调用存在着一定的差别, 它们都不会阻塞进程,都属于非阻塞系统调用, 但是返回结果的方式和内容有所差别
- 非阻塞 I/O 系统 调用
read()操作立即返回的是任何可以立即拿到的数据, 可以是完整的结果, 也可以是不完整的结果, 还可以是一个空值 - 异步 I/O 系统调用
read()结果必须是完整的, 但是这个操作完成的通知可以延迟到将来的一个时间点
非阻塞系统调用的存在可以用来实现线程级别的 I/O 并发, 与通过多进程实现的 I/O 并发相比可以减少内存消耗以及进程切换的开销
同步 IO 和异步 IO
同步IO:用户进程发出IO调用,去获取IO设备数据,双方的数据要经过内核缓冲区同步,完全准备好后,再复制返回到用户进程。而复制返回到用户进程会导致请求进程阻塞,直到I/O操作完成。
异步IO:用户进程发出IO调用,去获取IO设备数据,并不需要同步,内核直接复制到进程,整个过程不导致请求进程阻塞。