2011-01-06 7 views
6

Clojureの並行処理に関するさまざまなドキュメントを読み、Webサイト(http://clojure.org/concurrent_programming)の例を参照して説明しました。Clojureの同時実行の例を理解する

(import '(java.util.concurrent Executors)) 
(defn test-stm [nitems nthreads niters] 
(let [refs (map ref (replicate nitems 0)) 
     pool (Executors/newFixedThreadPool nthreads) 
     tasks (map (fn [t] 
        (fn [] 
        (dotimes [n niters] 
         (dosync 
         (doseq [r refs] 
          (alter r + 1 t)))))) 
       (range nthreads))] 
(doseq [future (.invokeAll pool tasks)] 
    (.get future)) 
(.shutdown pool) 
(map deref refs))) 

私はそれが何を理解し、どのように動作しますが、2番目の匿名関数fn []が必要な理由私が得ることはありませんか?

多くのありがとう、

dusha

P.S.この2番目のfn []がなければ、NullPointerExceptionが発生します。

答えて

5

高次関数を用いた古典的な例である:FN内部fnをそのサンプルコードで

;; a function returns another function 
(defn make-multiplyer [times] 
    (fn [x] 
    (* x times))) 

;; now we bind returned function to a symbol to use it later 
(def multiply-by-two (make-multiplyer 2)) 

;; let's use it 
(multiply-by-two 100) ; => 200 

は同じように動作します。 mapが呼び出すと(fn [t](fn [] ...))、内部のfnが得られます。

(def list-of-funcs (map (fn [t] 
          (fn [] (* t 10))) ; main part 
         (range 5))) 
;; Nearly same as 
;; (def list-of-funcs (list (fn [] (* 0 10)) 
;;       (fn [] (* 1 10)) 
;;       ... 
;;       (fn [] (* 4 10)))) 


(for [i list-of-funcs] 
    (i)) 
; => (0 10 20 30 40) 

アップデート:そして、アレックスは、サンプルコードでタスクが.invokeAllに、次に渡される呼び出し可能オブジェクトのリストにバインドされて言ったように()。

2

最初のfnは、fnのseqを作成するためにマップが使用するもので、スレッドごとに1つです。これは、タスクが関数のseqであるためです!方法.invokeAllは()は、Java呼び出し可能、のRunnableおよびコンパレータインタフェースを実装Clojure.org: Special Forms

FNSから呼び出し可能オブジェクトのコレクション(Clojureの関数が呼び出し可能インタフェースを実装する)

を期待しています。ここ

関連する問題