2012-05-14 13 views
7

Clojure先物を理解しようとしています。共通のClojure書籍の例を見てきました。また、並列計算に先物が使用されている例もあります。Clojure先物を理解する

しかし、私は、誰かがO'ReillyのProgramming Clojureの本から適応された簡単な例の動作を説明できることを望んでいます。

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

私はこれを逆参照しようとすると、

(time @long-calculation) 

を行うことにより、それは私のマシン上で(0.045ミリ秒で)ほぼ瞬時に正しい結果(49999999.5億)を返しますが、。

しかし、私は実際の関数を呼び出すときに、その

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

のように(〜5000ミリ秒)私も正しい結果を得るが、かかる時間がはるかに大きいです。

将来を逆参照するとき、私の理解は、式が評価される新しいスレッドが作成されたことです。この場合、約5000ミリ秒かかることが予想されます。

どのように逆参照された未来が正しい結果をすぐに返すのでしょうか?

答えて

11

今後の計算は、別のスレッドで将来作成するとすぐに開始されます。将来は、それが完了するまで、ブロックを完了してから値を返していない場合、これは可能性(

  • :あなたのケースでは、計算はできるだけ早くあなたは間接参照は、2つのうちの1つを行います(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配列を使用するか型ヒントを行う代わりに、慣用的な機能コードを書くだけで、代わりにこれらの計算の結果を 'future'で書くことができますか? – endbegin

+2

先物はかなり軽量ですが、オーバーヘッドがありますので、極端に小さな計算には使用しないでください。並列計算をしたいのであれば、 'pmap'を使うことを検討してください。これは、フードの中で先物を使う' map'の同時バージョンです。あなたのコードが実際に数値的に集中している場合は、CPU時間を最大限に活用したい場合は、おそらくJava配列*と* pmap/futureの両方を使用することをお勧めします。 – mikera

+0

私はpmapを使いこなそうとしましたが、データサイズが "大きく"(もちろん、どれほど大規模な主観的なのか)だけ有用であることがわかりました。私は単純なデジタル信号処理関数を実装してClojureを学んできました。シングルプロセッサ/スレッドモードでseq抽象化を持つ関数型よりもネイティブJava配列を使用すると、速度が大幅に向上します。先物を使用するとスピードアップが非常に大きくなり、ネイティブコードか機能コードかを問わない。私は何かが明らかでないように感じる。 – endbegin

関連する問題