既然现在我们已经理解了同步与异步在各种场景下的意义(I hope so) , 那么对于程序员来说该怎样理解同步与异步呢?
我们先说同步调用 , 这是程序员最熟悉的场景 。
一般的函数调用都是同步的 , 就像这样:
funcA() {// 等待函数funcB执行完成funcB();// 继续接下来的流程}
funcA调用funcB , 那么在funcB执行完前 , funcA中的后续代码都不会被执行 , 也就是说funcA必须等待funcB执行完成 , 就像这样:
文章插图
图片
从上图中我们可以看到 , 在funcB运行期间funcA什么都做不了 , 这就是典型的同步 。
注意 , 一般来说 , 像这种同步调用 , funcA和funcB是运行在同一个线程中的 , 这是最为常见的情况 。
但值得注意的是 , 即使运行在两个不能线程中的函数也可以进行同步调用 , 像我们进行IO操作时实际上底层是通过系统调用(关于系统调用请参考《程序员应如何理解系统调用》)的方式向操作系统发出请求的 , 比如磁盘文件读取:
read(file, buf);
这就是我们在《读取文件时 , 程序经历了什么》中描述的阻塞式I/O , 在read函数返回前程序是无法继续向前推进的read(file, buf);// 程序暂停运行 , // 等待文件读取完成后继续运行
如图所示:文章插图
图片
只有当read函数返回后程序才可以被继续执行 。
注意 , 和上面的同步调用不同的是 , 函数和被调函数运行在不同的线程中 。
因此我们可以得出结论 , 同步调用和函数与被调函数是否运行在同一个线程是没有关系的 。
在这里我们还要再次强调 , 同步方式下函数和被调函数无法同时进行 。
同步编程对程序员来说是最自然最容易理解的 。
但容易理解的代价就是在一些场景下 , 同步并不是高效的 , 原因很简单 , 因为任务没有办法同时进行 。
接下来我们看异步调用 。
异步调用有同步调用就有异步调用 。
如果你真的理解了本节到目前为止的内容的话 , 那么异步调用对你来说不是问题 。
一般来说 , 异步调用总是和I/O操作等耗时较高的任务如影随形 , 像磁盘文件读写、网络数据的收发、数据库操作等 。
我们还是以磁盘文件读取为例 。
在read函数的同步调用方式下 , 文件读取完之前调用方是无法继续向前推进的 , 但如果read函数可以异步调用情况就不一样了 。
假如read函数可以异步调用的话 , 即使文件还没有读取完成 , read函数也可以立即返回 。
read(file, buff);// read函数立即返回// 不会阻塞当前程序
就像这样:文章插图
图片
可以看到 , 在异步这种调用方式下 , 调用方不会被阻塞 , 函数调用完成后可以立即执行接下来的程序 。
这时异步的重点就在于调用方接下来的程序执行可以和文件读取同时进行 , 从上图中我们也能看出这一点 , 这就是异步的高效之处 。
但是 , 请注意 , 异步调用对于程序员来说在理解上是一种负担 , 代码编写上更是一种负担 , 总的来说 , 上帝在为你打开一扇门的时候会适当的关上一扇窗户 。
有的同学可能会问 , 在同步调用下 , 调用方不再继续执行而是暂停等待 , 被调函数执行完后很自然的就是调用方继续执行 , 那么异步调用下调用方怎知道被调函数是否执行完成呢?
这就分为了两种情况:
- 调用方根本就不关心执行结果
- 调用方需要知道执行结果
第二种情况下就比较有趣了 , 通常有两种实现方式:
一种是通知机制 , 也就是说当任务执行完成后发送信号来通知调用方任务完成 , 注意这里的信号有很多实现方式 , linux中的signal , 或者使用信号量等机制都可以实现 。
推荐阅读
- 既然有 HTTP 协议,为什么还要有 RPC
- 关于接口测试,你了解多少?
- 恨嫁什么意思 恨嫁的表现
- 梦见葫芦是什么意思 已婚女人梦见葫芦是什么意思
- 王者荣耀:不管什么版本为啥总有人只喜欢玩一个英雄?
- 你知道什么是非线性量化吗
- 英雄联盟中为什么德莱厄斯是最容易拿5杀的英雄?
- 梦见死人和棺材是什么兆头 梦见死人和棺材什么预兆
- 梦见讨论是什么意思呀 梦见讨论是什么意思
- 梦见蛇追我是什么预兆 梦见蛇追我是什么预兆 女性解梦