CSDN从小白到高手,10 图教你同步与异步( 四 )


本文插图
看到了吧 , 接下来重点来了哦 。 我们说过一个请求需要经过七个步骤 , 其中前三个是在主线程中完成的 , 后四个是在数据库线程中完成的 , 那么数据库线程是怎么知道查完数据库后要处理D、E、F这几个步骤呢?这时 , 我们的另一个主角回调函数就开始登场啦 。 没错 , 回调函数就是用来解决这一问题的 。 我们可以将处理D、E、F这几个步骤封装到一个函数中 , 假定将该函数命名为handle_DEF_after_DB_query:void handle_DEF_after_DB_query { D; E; F;}
这样主线程在发送数据库查询请求的同时将该函数一并当做参数传递过去:DB_query(request, handle_DEF_after_DB_query);数据库线程处理完后直接调用handle_DEF_after_DB_query就可以了 , 这就是回调函数的作用 。 也有的同学可能会有疑问 , 为什么这个函数要传递给数据库线程而不是数据库线程自己定义自己调用呢?
因为从软件组织结构上讲 , 这不是数据库线程该做的工作 。
数据库线程需要做的仅仅就是查询数据库、然后调用一个处理函数 , 至于这个处理函数做了些什么数据库线程根本就不关心 , 也不应该关心 。
你可以传入各种各样的回调函数 。 也就是说数据库系统可以针对回调函数这一抽象的函数变量来编程 , 从而更好的应对变化 , 因为回调函数的内容改变不会影响到数据库线程的逻辑 , 而如果数据库线程自己定义处理函数那么这种设计就没有灵活性可言了 。
而从软件开发的角度看 , 假设数据库线程逻辑封装为了库提供给其它团队 , 当数据库团队在研发时怎么可能知道数据库查询后该做什么呢?
显然 , 只有使用方才知道查询完数据库后该做些什么 , 因此使用方在使用时简单的传入这个回调函数就可以了 。
这样复杂数据库的团队就和使用方团队实现了所谓的解耦 。
现在你应该明白回调函数的作用了吧 。
不容易啊 , 容我喝口水叉会儿腰歇一歇 。
我们继续 。
另外仔细观察上面两张图 , 你能看出为什么异步比同步高效吗?
原因很简单 , 这也是我们在本篇提到过的 , 异步天然就无需等待 , 无依赖 。
从上一张图中我们可以看到主线程的“休闲时光”不见了 , 取而代之的是不断的工作、工作、工作 , 就像苦逼的996程序员一样 , 而且数据库线程也没有那么大段大段的空闲了 , 取而代之的也是工作、工作、工作 。
CSDN从小白到高手,10 图教你同步与异步
本文插图
主线程处理请求和数据库处理查询请求可以同时进行 , 因此从系统性能上看 , 这样的设计能更加充分的利用系统资源 , 更加快速的处理请求;从用户的角度看 , 系统的响应也会更加迅速 。
这就是异步的高效之处 。
但我们应该也可以看出 , 异步编程并不如同步来的容易理解 , 系统可维护性上也不如同步模式 。
那么有没有一种方法既能结合同步模式的容易理解又能结合异步模式的高效呢?答案是肯定的 , 我们将在后续章节详细讲解这一技术 。
接下来我们看第二种情况 , 那就是主线程需要关心数据库查询结果 。
2. 主线程关心数据库操作结果
在这种情况下 , 数据库线程需要将查询结果利用通知机制发送给主线程 , 主线程在接收到消息后继续处理上一个请求的后半部分 , 就像这样:
CSDN从小白到高手,10 图教你同步与异步
本文插图
从这里我们可以看到 , ABCDEF几个步骤全部在主线中处理 , 同时主线程同样也没有了“休闲时光” , 只不过在这种情况下数据库线程是比较清闲的 , 从这里并没有上一种方法高效 , 但是依然要比同步模式下要高效 。
最后需要注意的是 , 并不是所有的情况下异步都一定比同步高效 , 还需要结合具体业务以及IO的复杂度具体情况具体分析 。


推荐阅读