Я рекомендую вам использовать библиотеку параллелизма, мне очень нравится библиотека lparallel
У него есть красивые утилиты для распараллеливания вашего кода между всеми процессорами вашей машины. Это пример для моего macbook pro (4 ядра) с использованием SBCL. Существует множество примеров параллелизма и параллелизма Common Lisp здесь
Но давайте создадим пример с родственными lparallel, обратите внимание, что этот пример не является хорошим упражнением в параллелизме, он только для того, чтобы показать силу leparallel и простоту его использования.
Рассмотрим рекурсивную функцию хвоста Фибоначчи из cliki:
(defun fib (n) "Хвост-рекурсивное вычисление n-го элемента последовательности Фибоначчи" (check-type n (integer 0 *)) (labels ((fib-aux (n f1 f2) (if (zerop n) f1 (fib-вспомогательная (1- n) f2 (+ f1 f2))))) (fib-вспомогательная n 0 1)))
Это будет пример алгоритма высокой стоимости вычислений. давайте использовать его:
CL-USER> (time (progn (fib 1000000) nil))
Evaluation took:
17.833 seconds of real time
18.261164 seconds of total run time (16.154088 user, 2.107076 system)
[ Run times consist of 3.827 seconds GC time, and 14.435 seconds non-GC time. ]
102.40% CPU
53,379,077,025 processor cycles
43,367,543,984 bytes consed
NIL
это расчет 1000000-го члена ряда Фибоначчи на моем компьютере.
Давайте, например, вычислим список чисел фибонначи с помощью mapcar:
CL-USER> (time (progn (mapcar #'fib '(1000000 1000001 1000002 1000003)) nil))
Evaluation took:
71.455 seconds of real time
73.196391 seconds of total run time (64.662685 user, 8.533706 system)
[ Run times consist of 15.573 seconds GC time, and 57.624 seconds non-GC time. ]
102.44% CPU
213,883,959,679 processor cycles
173,470,577,888 bytes consed
NIL
У Lparallell есть родственные слова:
Они возвращают те же результаты, что и их аналоги из CL, за исключением случаев, когда параллелизм должен играть роль. Например, premove ведет себя практически так же, как его версия для CL, но por немного отличается. или возвращает результат первой формы, которая оценивается как нечто отличное от нуля, в то время как por может возвращать результат любой такой формы, не равной нулю.
первая загрузка lparallel:
CL-USER> (ql:quickload :lparallel)
To load "lparallel":
Load 1 ASDF system:
lparallel
; Loading "lparallel"
(:LPARALLEL)
Итак, в нашем случае единственное, что вам нужно сделать, это изначально ядро с доступным вам количеством ядер:
CL-USER> (setf lparallel:*kernel* (lparallel:make-kernel 4 :name "fibonacci-kernel"))
#<LPARALLEL.KERNEL:KERNEL :NAME "fibonacci-kernel" :WORKER-COUNT 4 :USE-CALLER NIL :ALIVE T :SPIN-COUNT 2000 {1004E1E693}>
а затем запустите родственников из семейства pmap:
CL-USER> (time (progn (lparallel:pmapcar #'fib '(1000000 1000001 1000002 1000003)) nil))
Evaluation took:
58.016 seconds of real time
141.968723 seconds of total run time (107.336060 user, 34.632663 system)
[ Run times consist of 14.880 seconds GC time, and 127.089 seconds non-GC time. ]
244.71% CPU
173,655,268,162 processor cycles
172,916,698,640 bytes consed
NIL
Вы можете видеть, как легко распараллелить эту задачу, у lparallel есть много ресурсов, которые вы можете изучить:
Я также добавляю данные об использовании процессора с первого mapcar и pmapcar на моем Mac:
![первая загрузка - это mapcar, а вторая - из lparallel](https://i.stack.imgur.com/GOCxK.png)
person
anquegi
schedule
23.10.2016