Доступ к массиву никогда не бывает последовательным, если только это не массивы, а ленивые последовательности. Этого не должно быть, потому что массивы неизменны - это отличительная черта Clojure. Ваше замедление не происходит от этого.
Ваша идея распараллеливания верна, посмотрите на это:
(defn fibonacci [n] (case n 1 1 2 1 (+ (fibonacci (- n 2)) (fibonacci (- n 1)))))
(defn parallel-fib []
(let [s1 (future (fibonacci 34))
s2 (future (fibonacci 35))
s3 (future (fibonacci 36))
s4 (future (fibonacci 33))]
[@s1 @s2 @s3 @s4]))
user=> (time (fibonacci 35))
"Elapsed time: 1514.663902 msecs"
9227465
user=> (time (fibonacci 36))
"Elapsed time: 2403.761528 msecs"
14930352
user=> (time (parallel-fib))
"Elapsed time: 2552.572043 msecs"
[5702887 9227465 14930352 3524578]
Очевидно, что параллельно выполняемые фьючерсы, работающие на 4-ядерном компьютере, дают время, близкое к самым дорогим вычислениям, а не к сумме времени вычислений.
Таким образом, я не вижу очевидных причин, по которым ваш код работает в разы ближе к последовательному выполнению. Причины, которые приходят мне в голову, могут быть:
fun1 (или любая другая из этих забав) может быть параллельной функцией (например, с использованием pmap), потребляющей все ваши ядра. Тогда процессор будет забит и никакого ускорения не будет наблюдаться.
Каким-то образом 'сцепление' потребляет много ресурсов процессора, чтобы собрать результаты. Это не должно быть большой проблемой, как если бы вы использовали стандартный Clojure 'concat', он создает ленивую последовательность, которая должна нести стоимость доступа только после того, как к ней обращаются. Не говоря уже о том, что стоимость доступа должна быть очень низкой.
Если вычисления внутри фьючерсов очень просты, хорошее масштабирование также не может быть заархивировано. Мы знаем, что это неправда, потому что вы уже упоминали, что на это нужно потратить 10 секунд.
Может помочь, если вы отправите мне весь код. Мой электронный адрес: контакт [at] spinney.io.