2012-05-14 158 views
7

我想了解Clojure期貨,並且我已經看到了常見Clojure書籍的例子,並且有些例子中期貨被用於並行計算(這似乎是有道理的)。瞭解Clojure期貨

但是,我希望有人能夠解釋O'Reilly編程Clojure書中一個簡單例子的行爲。

(def long-calculation (future (apply + (range 1e8)))) 

當我嘗試取消引用此,通過做

(time @long-calculation) 

它返回正確的結果(49999999.5億),但幾乎瞬間(0.045毫秒)我的機器上。

但是當我打電話的實際功能,像這樣

(time (apply + (range 1e8))) 

我得到正確的結果爲好,但花費的時間要大得多(〜5000毫秒)。

當我對未來進行解引用時,我的理解是創建一個新的線程來評估表達式 - 在這種情況下,我預計它也需要大約5000毫秒。

爲什麼取消引用的未來如此快速地返回正確的結果?

回答

11

未來的計算會在創建未來時開始(在單獨的線程中)。

  • 如果未來還沒有完成,塊直到它完成,然後返回值(這可能:在你的情況下,計算只要你執行(def long-calculation ....)

    提領將做兩件事情之一開始採取任意的時間,甚至從未完成,如果未來未能終止)

  • 如果未來已完成,則返回結果。這幾乎是瞬時的(這就是爲什麼你看到非常快提領收益)

可以通過對比看到效果如下:

;; dereference before future completes 
(let [f (future (Thread/sleep 1000))] 
    (time @f)) 
=> "Elapsed time: 999.46176 msecs" 

;; dereference after future completes 
(let [f (future (Thread/sleep 1000))] 
    (Thread/sleep 2000) 
    (time @f)) 
=> "Elapsed time: 0.039598 msecs" 
+0

有沒有使用大量的期貨的缺點?我一直在編寫一些在很多地方進行數值計算的代碼。我可以不用原生的Java數組或類型提示,而只是編寫慣用的函數代碼和「將來」這些計算的結果呢? – endbegin

+2

期貨相當輕量級,但確實有一些開銷,所以我會避免使用它們進行極小的計算。如果你想同時進行計算,可以考慮使用'pmap' - 這是'map'的併發版本,它使用期貨下的期貨。話雖如此,如果您的代碼真的是數字密集型的,那麼如果您希望儘可能地利用CPU時間,那麼最好使用Java數組*和* pmap/futures。 – mikera

+0

我嘗試過使用pmap,但是隻有當數據大小「很大」時(當然有多大才是主觀的),它纔會有用。我一直在通過實現一些簡單的數字信號處理函數來學習Clojure,並且在單處理器/線程模式下使用本地Java數組的功能風格與seq抽象相比具有明顯的速度優勢。如果我使用期貨,加速是如此巨大,以至於我使用本地代碼還是功能代碼都無關緊要。感覺像我失去了一些明顯的東西。 – endbegin