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


但是 , 请注意 , 异步调用对于程序员来说在理解上是一种负担 , 代码编写上更是一种负担 , 总的来说 , 上帝在为你打开一扇门的时候会适当的关上一扇窗户 。
有的同学可能会问 , 在同步调用下 , 调用方不再继续执行而是暂停等待 , 被调函数执行完后很自然的就是调用方继续执行 , 那么异步调用下调用方怎知道被调函数是否执行完成呢?
这就分为了两种情况:

  1. 调用方根本就不关心执行结果
  2. 调用方需要知道执行结果
第一种情况比较简单 , 无需讨论 。
第二种情况下就比较有趣了 , 通常有两种实现方式:
一种是通知机制 , 也就是说当任务执行完成后发送信号来通知调用方任务完成 , 注意这里的信号有很多实现方式 , Linux中的signal , 或者使用信号量等机制都可以实现 。
另一种是就是回调 , 也就是我们常说的callback , 关于回调我们将在下一篇文章中重点讲解 , 本篇会有简短的讨论 。
接下来我们用一个具体的例子讲解一下同步调用与异步调用 。
同步 vs 异步我们以常见的Web服务来举例说明这一问题 。
一般来说Web Server接收到用户请求后会有一些典型的处理逻辑 , 最常见的就是数据库查询(当然 , 你也可以把这里的数据库查询换成其它I/O操作 , 比如磁盘读取、网络通信等) , 在这里我们假定处理一次用户请求需要经过步骤A、B、C , 然后读取数据库 , 数据库读取完成后需要经过步骤D、E、F , 就像这样:
# 处理一次用户请求需要经过的步骤:A;B;C;数据库读取;D;E;F;
其中步骤A、B、C和D、E、F不需要任何I/O , 也就是说这六个步骤不需要读取文件、网络通信等 , 涉及到I/O操作的只有数据库查询这一步 。
一般来说这样的Web Server有两个典型的线程:主线程和数据库处理线程 , 注意 , 这讨论的只是典型的场景 , 具体业务实际上可会有差别 , 但这并不影响我们用两个线程来说明问题 。
首先我们来看下最简单的实现方式 , 也就是同步 。
这种方式最为自然也最为容易理解:
// 主线程main_thread { A; B; C; 发送数据库查询请求; D; E; F;}// 数据库线程DataBase_thread {while(1) { 处理数据库读取请求; 返回结果; }}
这就是最为典型的同步方法 , 主线程在发出数据库查询请求后就会被阻塞而暂停运行 , 直到数据库查询完毕后面的D、E、F才可以继续运行 , 就像这样:
CSDN从小白到高手,10 图教你同步与异步
本文插图
从图中我们可以看到 , 主线程中会有“空隙” , 这个空隙就是主线程的“休闲时光” , 主线程在这段休闲时光中需要等待数据库查询完成才能继续后续处理流程 。
在这里主线程就好比监工的老板 , 数据库线程就好比苦逼搬砖的程序员 , 在搬完砖前老板什么都不做只是紧紧的盯着你 , 等你搬完砖后才去忙其它事情 。
显然 , 高效的程序员是不能容忍主线程偷懒的 。
是时候祭出大杀器了 , 这就是异步 。
在异步这种实现方案下主线程根本不去等待数据库是否查询完成 , 而是发送完数据库读写请求后直接处理下一个请求 。
有的同学可能会有疑问 , 一个请求需要经过A、B、C、数据库查询、D、E、F这七个步骤 , 如果主线程在完成A、B、C、数据库查询后直接进行处理接下来的请求 , 那么上一个请求中剩下的D、E、F几个步骤怎么办呢?
如果大家还没有忘记上一小节内容的话应该知道 , 这有两种情况 , 我们来分别讨论 。
1 , 主线程不关心数据库操作结果
在这种情况下 , 主线程根本就不关心数据库是否查询完毕 , 数据库查询完毕后自行处理接下来的D、E、F三个步骤 , 就像这样:
CSDN从小白到高手,10 图教你同步与异步


推荐阅读