суббота, 9 марта 2013 г.

Новое в clojure 1.5

1 марта был выпущен релиз clojure 1.5. Полный список изменений здесь https://github.com/clojure/clojure/blob/master/changes.md

Теперь для версии clojure 1.5 требуется Java 7 (используется класс java.util.concurrent.ForkJoinPool). Новая версия Java необходима для работы с новым добавленным неймспейсом clojure.core.reducers

Новая библиотека core.reducers призвана увеличить скорость обработки коллекций. Основная оптимизация заключается в том, что последовательность действий над коллекцией (например (filter #() (map #() seq))) не создает промежуточную коллекцию и действия могут выполняться параллельно(при этом код остаётся без изменений)

clojure-1-5.core=> (require ['clojure.core.reducers :as 'r])
nil
clojure-1-5.core=> (def numbers (into [] (range 99999)))
#'clojure-1-5.core/numbers
clojure-1-5.core=> (time (doseq [x (range 100)] (reduce + (r/filter #(> 4 (mod %1 10)) (r/map inc numbers)))))
"Elapsed time: 729.914422 msecs"
nil
clojure-1-5.core=> (time (doseq [x (range 100)] (reduce + (filter #(> 4 (mod %1 10)) (map inc numbers)))))
"Elapsed time: 847.422309 msecs"
nil

Для агентов появилась возможность задать собственный пул тредов для выполнения модифицирующих операций над агентами(с помощью send, send-of, send-via)
Например можно выполнять операции над агентами в один поток(по умолчанию число потоков равно числу ядер + 2)
clojure-1-5.core=> (def a (agent {:a 1}))
#'clojure-1-5.core/a
clojure-1-5.core=> @a
{:a 1}
clojure-1-5.core=> (send a assoc :b 2)
#<Agent@17d577c: {:a 1, :b 2}>
clojure-1-5.core=> @a
{:a 1, :b 2}
clojure-1-5.core=> (set-agent-send-executor! (java.util.concurrent.Executors/newSingleThreadExecutor))
#<FinalizableDelegatedExecutorService java.util.concurrent.Executors$FinalizableDelegatedExecutorService@108fbd4>
clojure-1-5.core=> (send a assoc :c 3)
#<Agent@17d577c: {:a 1, :c 3, :b 2}>
clojure-1-5.core=> @a
{:a 1, :c 3, :b 2}

Для кастомизации функции send используется set-agent-send-executor! для send-off используется  set-agent-send-off-executor!. Если нужно выполнить действие над агентом с произвольным исполнителем, можно использовать send-via.  В общем случае функцию send следует использовать когда операция занимает фиксированное количество времени, а send-off когда операция может быть заблокирована по I/O или другому внешнему ресурсу.

Начиная с версии 1.5 функции-конструкторы (hash-map, array-map) принимают дублирующие значения ключей и не выкидывают исключения

в версии 1.4
(hash-map :a 1 :b 2 :a 4)
IllegalArgumentException Duplicate key: :a  clojure.lang.PersistentHashMap.createWithCheck (PersistentHashMap.java:92)
в 1.5
(hash-map :a 1 :b 2 :a 4)
{:a 4, :b 2}
объявление литерала c дублирующими ключами по прежнему кидает исключение

{:a 1 :b 2 :a 4}
#<IllegalArgumentException java.lang.IllegalArgumentException: Duplicate key: :a>

К макросам -> ->> добавилось несколько новых макросов cond-> и cond->> для выполнения последовательности действий с условиями, а также есть возможность задать именнованную область с помощью as->

(-> 84
           (/ 4)
           (as-> twenty-one
                  (* 2 twenty-one)))
42
Для последовательности действий, где на промежуточном шаге результат действия может быть nil и необходимо прервать выполнение дальнейших шагов есть макрос some-> (или some->>)

(-> (range 1) next inc)
NullPointerException   [trace missing]
(some-> (range 1) next inc)
nil


Новая версия gen-class позволяет обращаться к protected final методам родительского класса через :exposes-methods

К мета данным (функция meta) добавлен атрибут :column, указывающий номер колонки в исходном файле. До версии 1.5 был указан только номер строки :line

1 комментарий:

  1. насчет Java 7 - не совсем точно. Оно может работать и с 6-й версией, при явном добавлении библиотеки для fork/join и даже с 5-й версией, если reducers не будут использоваться

    ОтветитьУдалить