Понимание примера параллелизма Clojure
Я просто просматриваю различную документацию по параллелизму Clojure и перехожу к примеру на веб-сайте (http://clojure.org/concurrent_programming).
(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)))
Я понимаю, что он делает и как он работает, но я не понимаю, зачем нужна вторая анонимная функция FN []?
большое спасибо,
душа.
P. S. Без этой второй ФН [] я получаю исключение NullPointerException.
2 ответов
вот классический пример использования функций высшего порядка:
;; 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
в этом примере кода FN внутри fn работает одинаково. Когда 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)
Update: и, как сказал Алекс, задачи в примере кода привязаны к списку вызываемых, который передается затем .разветвляет().
первый fn-это то, что map использует для создания seq fn - по одному для каждого из потоков. Это потому, что задачи-это seq функций! Метод. invokeAll () ожидает коллекцию вызываемых объектов (функции Clojure реализуют вызываемый интерфейс)
от Clojure.org: Специальные Формы
FNS реализует вызываемые, запускаемые и компаратор интерфейсы Java.