Модуль std.parallelism
реализует высокоуровневые
примитивы для удобной организации параллельного программирования.
std.parallelism.parallel
позволяет автоматически распределить
тело цикла foreach
между разными потоками:
// параллельно возвести в квадрат
// элементы arr
auto arr = iota(1,100).array;
foreach(ref i; parallel(arr)) {
i = i*i;
}
Внутри parallel
используется оператор opApply
.
Глобальная функция parallel
- это упрощённый
вариант вызова taskPool.parallel
. Она применяет
TaskPool
, использующий количество рабочих потоков,
равное общему числу процессоров - 1. Создание
отдельного пула позволяет назначить степень
параллелизма.
Обратите внимание, тело parallel
-итерации не
должно изменять элементы, к которым может иметь
доступ другая рабочая единица.
Опциональный параметр workingUnitSize
задаёт
количество элементов, обрабатываемых каждым
потоком.
Функция
std.algorithm.iteration.reduce
,
известная в других функциональных контекстах как accumulate
или foldl, вызывает функцию fun(acc, x)
для каждого элемента
x
, передавая через acc
предыдущий результат:
// 0 - начальное значение
auto sum = reduce!"a + b"(0, elements);
Taskpool.reduce
-
это параллельный аналог reduce
:
// Вычислить сумму диапазона параллельно, используя
// первый элемент каждой рабочей единицы как начальное значение
auto sum = taskPool.reduce!"a + b"(nums);
TaskPool.reduce
разделяет диапазон на поддиапазоны,
которые обрабатываются параллельно. Как только результаты
от отдельных поддиапазонов становятся известны,
они так же обрабатываются.
task()
task
- это обёртка для функции,
исполнение которой может занять значительное время
или которую следует исполнить в собственном рабочем
потоке. Её можно поставить в очередь пула задач:
auto t = task!read("foo.txt");
taskPool.put(t);
или же непосредственно исполнить в отдельном новом потоке:
t.executeInNewThread();
Чтобы получить результат задачи, необходимо вызвать yieldForce
.
Этот вызов блокирует текущий поток до тех пор, пока
не будет получен результат.
auto fileData = t.yieldForce;