当前位置: 华文星空 > 知识

回调函数(callback)是什么?

2011-08-05知识

随便讲讲我的理解。

callback概念解释

这是非常普通的一次方法调用(method call):

一般来说,method()的调用耗时很短,也就几毫秒。但如果method()内部涉及磁盘IO或者method()干脆就是网络调用(网络IO),可能就比较耗时了。至于多久才称得上「耗时」,不太好定义。当前案例中,不妨理解为:客户端无法忍受得到最终结果所耗费的时间。

main线程必须等待method返回结果后才能继续往下走

如何解决耗时操作呢?你可能很容易就想到「异步」:

这里的「异步」,指的是狭隘的「开启一个子线程」。但是上面这个图 并不完整 ,原本的代码里method()是有result的:

由于要获取method的返回值,所以看起来好像同步的,但确实是thread-0在处理method

你可能很容易就想到了两种方案:

  • main()自己开启一个循环,不停地问method:好了没、好了没...,直到有结果
  • 阻塞等待
  • 这里只是简单地设想两种获取子线程结果的方式

    但实际上,对于调用方而言两种方式是一样的,它都要等待这个method耗时操作完成才能收到result,然后才能执行后面的domething later操作。

    于是产生了矛盾:

  • do something依赖于method的result
  • 但method很慢
  • 而我希望尽快do something并返回
  • 比较好的处理方式是:

    既然do something依赖于method的result,那么do something应该和method共同处理,所以我把do something挪到method内部
    左图看似用了异步线程,但由于要获取异步结果,产生了阻塞等待,并没有把异步的功效最大化!

    怎么把do something挪到method里面呢?

    由于do something的需求各种各样,是不确定的,不能在method里写死。为了能让method()帮我们执行自定义的操作, method()必须再提供一个入参:

    callback()具有特异性,只有调用方才知道要做什么样的处理,所以要定义在调用侧,也就是和main()在一块。

    有call,有back,所以叫callback

    callback与设计模式

    callback和策略模式很像,但个人觉得还是细微差别,主要是出发点不同。

    这是callback:

    这是策略模式:

    策略模式一般都是被调用方预先定义几种策略供选择,比如线程池拒绝策略。但我们自定义拒绝策略也是可以的

    你要说策略模式「有call有back」,所以也算callback,其实也说得通...但两者出发点是不同的。当前案例可能看不出来,再举一个例子可能更好理解。

    比如跨系统的callback:

    这个时候你很难称之为「策略模式」。

    还有观察者模式也是如此,看起来也和callback很像,但出发点也多少有点区别。观察者模式出发点是当事件源发生改变时收到通知,而callback更像是有妥协的步骤拆分。

    当然,还是那句话,你要是觉得这几个本质是一样的,那就这么认为也无妨,个人觉得没必要死扣定义。

    callback与IO模型

    很多人也学习过NIO和AIO,特别是AIO,定义了一个CompletionHandler接口:

    当某个I/O操作完成时,会自动回调completed(),我们实现completed()完成自己要做的操作。

    总的来说,callback可大可小,宏观的有JVM内的回调函数、系统间的回调接口,微观的有操作系统的回调机制,甚至脱口秀也有callback。

    博主最近新写的小册,图文并茂,通俗易懂:

    还有2024年新写的【设计模式那些事儿】: