Clojure вычислительный массив параллельно - PullRequest
2 голосов
/ 10 июня 2019

Мне нужна помощь.У меня на массиве (последовательности) размером 4000 элементов.Мне нужно вычислить каждую часть (1000 элементов - одна часть) четырьмя различными функциями.На функциональных вычислениях одна часть не менее 10 сек.Другая функция вычисляет свои части за 1 сек.Мне нужно сделать это в списке 10 раз.Поэтому, конечно, я хочу сделать это параллельно.Я пытаюсь сделать это, используя будущее будущего, но это займет время вычислений, как программа последовательности.Сначала я думаю, это потому, что когда я использую один массив и отправляю данные каждой функции, каждый будущий поток может получить последовательный доступ.Как я могу делать эти вычисления параллельно?

вот простой пример кода:

(defn funct [t n]
 (let [ a (future (fun1 (fun_take_i_part_array n 1)))
        b (future (fun2 (fun_take_i_part_array n 2)))
        c (future (fun3 (fun_take_i_part_array n 3)))
        d (future (fun4 (fun_take_i_part_array n 4)))
      ]
 (concatenate @a @b @c @d)
 )

)

Так что эта программа будущего типа будет длиться дольше, чем последовательность в течение 1 секунды.

1 Ответ

1 голос
/ 11 июня 2019

Доступ к массиву никогда не бывает последовательным, если только это не массивы, а ленивые последовательности. Этого не должно быть, потому что массивы неизменны - это отличительная черта 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-ядерном компьютере, дают время, близкое к самым дорогим вычислениям, а не к сумме времени вычислений.

Таким образом, я не вижу очевидных причин, по которым ваш код работает в разы ближе к последовательному выполнению. Причины, которые приходят мне в голову, могут быть:

  1. fun1 (или любая другая из этих забав) может быть параллельной функцией (например, с использованием pmap), потребляющей все ваши ядра. Тогда процессор будет забит и никакого ускорения не будет наблюдаться.

  2. Каким-то образом 'сцепление' потребляет много ресурсов процессора, чтобы собрать результаты. Это не должно быть большой проблемой, как если бы вы использовали стандартный Clojure 'concat', он создает ленивую последовательность, которая должна нести стоимость доступа только после того, как к ней обращаются. Не говоря уже о том, что стоимость доступа должна быть очень низкой.

  3. Если вычисления внутри фьючерсов очень просты, хорошее масштабирование также не может быть заархивировано. Мы знаем, что это неправда, потому что вы уже упоминали, что на это нужно потратить 10 секунд.

Может помочь, если вы отправите мне весь код. Мой электронный адрес: контакт [at] spinney.io.

...