Есть ли способ выполнять формы параллельно в Common Lisp? Что-то вроде параллельного PROGN?

Вопрос или проблема

У меня есть последовательность присваиваний массива:

...
(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.

Оцените материал
Добавить комментарий

Капча загружается...