Вопрос или проблема
У меня есть последовательность присваиваний массива:
...
(incf (aref res 1) formula1)
(incf (aref res 2) formula2)
...
Формула i — это какой-то сложный автоматически сгенерированный код, который очень отличается для каждого i. Этот код генерируется во время компиляции – это алгебраическое выражение, а не макрос или функция.
Что я хочу, так это обернуть эти утверждения во что-то вроде “параллельного прогноза”, чтобы присваивания распределялись по различным потокам-работникам. Порядок выполнения не имеет значения, так как каждый индекс присваивается ровно один раз.
Я не вижу, как вписать эту задачу в абстракции lparallel, но, возможно, я чего-то не понимаю. Похоже, что ни pmap, ни plet, ни futures не подходят для этой задачи.
Ответ или решение
Да, в Common Lisp действительно можно выполнять формы параллельно, используя разные подходы для достижения этой цели. Если вам нужно выполнить несколько независимых вычислений, например, инкрементировать элементы массива, не заботясь о порядке их выполнения, вы можете воспользоваться библиотеками параллелизма, такими как lparallel
или bordeaux-threads
.
Рассмотрим возможное решение с использованием библиотеки lparallel
, которая предоставляет простые средства для параллельного программирования. Приведем пример того, как можно реализовать ваше желание по параллельному выполнению следующих операций:
(ql:quickload :lparallel)
(defun parallel-update (res formulas)
(let ((futures (mapcar (lambda (i formula)
(lparallel:futures:make-future
(lambda ()
(incf (aref res i) formula))))
(loop for i from 0 below (length formulas) collect i)
formulas)))
(mapcar #'lparallel:futures:get futures)))
;; Пример использования
(let ((res (make-array 10 :initial-element 0))
(formulas (list formula1 formula2 ... formulaN)))
(parallel-update res formulas)
res)
В данном примере мы определяем функцию parallel-update
, которая принимает результирующий массив res
и список формул. Для каждой формулы создается будущее с использованием lparallel:futures:make-future
, что позволяет выполнять вычисления в отдельных потоках. Затем результаты собираются с помощью lparallel:futures:get
. Поскольку mapcar
обрабатывает каждую пару индекса и формулы, каждое вычисление выполняется в своем потоке.
Такая стратегия позволяет вам легко расширять список формул без необходимости заботиться о менеджменте потоков вручную. Основное здесь – это использование futures
, которые обеспечивают простоту в работе с параллелизмом и позволяют избежать блокировок, так как каждая задача запускается асинхронно.
Кроме того, обратите внимание на библиотеку bordeaux-threads
, если вам нужно более низкоуровневое управление потоками и синхронизацией, однако для вашего случая использования lparallel
будет более удобным.
Таким образом, ваше требование по параллельному выполнению операций можно легко реализовать путем использования библиотек параллелизма в Common Lisp.