一篇文章让你彻底理解回调函数( 二 )

这样你就不用死盯着屏幕了,因为你把make_youtiao这个函数执行完后该做的任务交代给make_youtiao这个函数了,该函数制作完油条后知道该干些什么,这样就解放了你的程序 。
有的同学可能还是有疑问,为什么编写make_youtiao这个小组不直接定义sell函数然后调用呢?
不要忘了明日油条这个App是由A小组和B小组同时开发的,A小组在编写make_youtiao时怎么知道B小组要怎么用这个模块,假设A小组真的自己定义sell函数就会这样写:
void make_youtiao(int num) { real_make_youtiao(num); sell(); //执行回调 }同时A小组设计的模块非常好用,这时C小组也想用这个模块,然而C小组的需求是制作完油条后放到仓库而不是不是直接卖掉,要满足这一需求那么A小组该怎么写呢?
void make_youtiao(int num) { real_make_youtiao(num);if (Team_B) { sell(); // 执行回调 } else if (Team_D) { store(); // 放到仓库 }}故事还没完,假设这时D小组又想使用呢,难道还要接着添加if else吗?这样的话A小组的同学只需要维护make_youtiao这个函数就能做到工作量饱满了,显然这是一种非常糟糕的设计 。
所以你会看到,制作完油条后接下来该做什么不是实现make_youtiao的A小组该关心的事情,很明显只有调用make_youtiao这个函数的使用方才知道 。
因此make_youtiao的A小组完全可以通过回调函数将接下来该干什么交给调用方实现,A小组的同学只需要针对回调函数这一抽象概念进行编程就好了,这样调用方在制作完油条后不管是卖掉、放到库存还是自己吃掉等等想做什么都可以,A小组的make_youtiao函数根本不用做任何改动,因为A小组是针对回调函数这一抽象概念来编程的 。
以上就是回调函数的作用,当然这也是针对抽象而不是具体实现进行编程这一思想的威力所在 。面向对象中的多态本质上就是让你用来针对抽象而不是针对实现来编程的 。
【文章福利】需要C/C++ Linux服务器架构师学习资料加群812855908(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等)

一篇文章让你彻底理解回调函数

文章插图
 
异步回调故事到这里还没有结束 。
在上面的示例中,虽然我们使用了回调这一概念,也就是调用方实现回调函数然后再将该函数当做参数传递给其它模块调用 。
但是,这里依然有一个问题,那就是make_youtiao函数的调用方式依然是同步的,也就是说调用方是这样实现的:
make_youtiao(10000, sell);// make_youtiao函数返回前什么都做不了
一篇文章让你彻底理解回调函数

文章插图
 
我们可以看到,调用方必须等待make_youtiao函数返回后才可以继续后续流程,我们再来看下make_youtiao函数的实现:
void make_youtiao(int num, func call_back) { real_make_youtiao(num); call_back(); //执行回调 }看到了吧,由于我们要制作10000个油条,make_youtiao函数执行完需要10分钟,也就是说即便我们使用了回调,调用方完全不需要关心制作完油条后的后续流程,但是调用方依然会被阻塞10分钟,这就是同步调用的问题所在 。
如果你真的理解了上一节的话应该能想到一种更好的方法了 。
没错,那就是异步调用 。
反正制作完油条后的后续流程并不是调用方该关心的,也就是说调用方并不关心make_youtiao这一函数的返回值,那么一种更好的方式是:把制作油条的这一任务放到另一个线程(进程)、甚至另一台机器上 。
如果用线程实现的话,那么make_youtiao就是这样实现了:
void make_youtiao(int num, func call_back) { // 在新的线程中执行处理逻辑 create_thread(real_make_youtiao, num, call_back);}
一篇文章让你彻底理解回调函数

文章插图
 
看到了吧,这时当我们调用make_youtiao时就会立刻返回,即使油条还没有真正开始制作,而调用方也完全无需等待制作油条的过程,可以立刻执行后流程:
make_youtiao(10000, sell);// 立刻返回// 执行后续流程这时调用方的后续流程可以和制作油条同时进行,这就是函数的异步调用,当然这也是异步的高效之处 。
新的编程思维模式让我们再来仔细的看一下这个过程 。程序员最熟悉的思维模式是这样的:
  • 调用某个函数,获取结果