當前位置: 華文星空 > 知識

回呼函式(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年新寫的【設計模式那些事兒】: