相信很多人在面试的过程中,都被问到过同步和异步的区别、阻塞和非阻塞的区别,以及这两对关系又有什么联系?本文尽可能从专业的角度,用易懂的语言,帮助大家理解
01 前置知识
用户空间和内核空间
操作系统可以支持多个进程同时运行,但需要保证不同进程之前不会相互影响(即一个进程不能恶意读取或修改其他进程中的数据)。因此将操作系统分为用户空间和内核空间,用户空间进行数据的处理,而对于数据的读写以及其他的调度和管理,则有内核空间处理
进程通信
两个进程通信的时候,都会将数据从用户空间的缓冲区拷贝到内核空间的缓冲区,然后将内核空间缓冲区的数据发送出去。接收的时候相反,会先把网络传输过来的数据放置到内核缓冲区中,然后再拷贝到用户空间的缓冲区中进行处理
02 相关概念
关于同步、异步、阻塞、非阻塞在《操作系统概念(第九版)》中有如下解释
结合上面的概念,通过进程A和B通信,来理解一下这几者的关系
- 同步
也就是图中的阻塞发送,A调用send()方法与B通信,由于是同步(阻塞发送),那么在A进程所对应的系统内核空间中,内核缓冲区的数据没发送出去之前,A进程都是一直等待的
- 异步
也就是图中的非阻塞发送,A调用send()方法与B通信,由于是异步(非阻塞发送),A进程只需要把要发送的消息由用户空间拷贝到内核空间,不用等到内核缓冲区的消息发送出去,就可以处理其他逻辑
- 阻塞
针对的是接收消息的一方,如果A给B要发送消息,B调用receive()方法,如果内核缓冲区中没有数据或者没有到达指定大小的数据,那么B进程就会一直阻塞,直到符合满足返回数据的条件
- 非阻塞
针对的是接受消息的一方,如果A给B要发送消息,B调用receive()方法,如果内核缓存区中没有数据,那么B就会返回一个空值,不会阻塞
03 阻塞是什么
无论是同步、异步还是阻塞、非阻塞,都离不开阻塞这个概念,那么阻塞到底是什么?下面用一幅图来表示一个进程的生命周期
- new:代表进程创建
- ready:进程等待操作系统调度
- running:操作系统调度,进程拿到cpu开始执行代码
- waiting:当发生IO、或者调用内核方法主动释放cpu,进入等待状态
- terminated:进程正常或异常结束
而阻塞就发生在waiting阶段,由于进程在running状态下发起了一个系统调用如(read()调用),该调用不能立即完成,需要等待一段时间,于是内核将该进程标记为waiting状态,也就是阻塞该进程,以确保它不会被cpu调度,浪费cpu资源(即使拿到了cpu,从内核空间获取数据没有准备好,也无法执行后续的逻辑)。
当内核把数据准备好之后,就会从waiting状态变为ready状态,等待操作系统的调用。
04 总结
- 同步和异步、阻塞和非阻塞本质上是一对相对的概念。
- 在进程通信这个层面,同步和异步针对的是发送方而言,取决于将数据写到内核缓冲区进程的行为,继续等待发送则为同步,反之即为异步。
- 在进程通信这个层面,阻塞非阻塞针对的是接收方而言,取决于将内核中的数据能否立即拷贝到用户空间,如果不能直接拷贝则为阻塞,反之则为非阻塞。
- 阻塞是进程的一种状态,由于cpu的速度远远高于磁盘速度,为了提高cpu利用率,对于涉及系统调用的进程(牵扯到磁盘读写),会把进程置为阻塞状态,防止cpu调度。