Работа с кодированными массивами

Как программное обеспечение MATLAB распределяет массивы

Когда вы распределяете массив ряду работников, MATLAB® программа разделяет массив на сегменты и присваивает каждый рабочий процесс по одному сегменту массива. Можно разбить двумерный массив по горизонтали, присвоив столбцы исходного массива различным работникам или вертикально, присвоив строки. Массив с N размерностями может быть разделен по любому из его N измерений. Вы выбираете, какая размерность массива будет разделяема, указав его в команде конструктора массива.

Для примера, чтобы распределить массив 80 на 1000 между четырьмя рабочими, можно разделить его либо по столбцам, предоставляя каждому рабочему сегмент 80 на 250, либо по строкам, при этом каждый рабочий получает сегмент 20 на 1000. Если измерение массива не разделяется равномерно по количеству работников, MATLAB разделяет ее максимально равномерно.

Следующий пример создает реплицированный массив 80 на 1000 и присваивает его переменной A. При этом каждый рабочий процесс создает идентичный массив в своей собственной рабочей области и присваивает его переменной A, где A является локальным для этого работника. Вторая команда распределяет A, создав один массив 80 на 1000 D это охватывает всех четырех рабочих. Рабочий 1 хранит столбцы с 1 по 250, рабочий 2 хранит столбцы с 251 по 500 и так далее. Распределение по умолчанию определяется последней размерностью несинглтона, таким образом, столбцами в этом случае 2-мерного массива.

spmd
  A = zeros(80, 1000);
  D = codistributed(A)
end

    Lab 1: This lab stores D(:,1:250).
    Lab 2: This lab stores D(:,251:500).
    Lab 3: This lab stores D(:,501:750).
    Lab 4: This lab stores D(:,751:1000).

Каждый рабочий процесс имеет доступ ко всем сегментам массива. Доступ к локальному сегменту происходит быстрее, чем к удаленному сегменту, поскольку последний требует отправки и приема данных между работниками и, таким образом, занимает больше времени.

Как MATLAB отображает кодированный массив

Для каждого рабочего процесса в MATLAB Parallel Командное Окно отображается информация о кодовом массиве, локальном фрагменте и кодовом распространителе. Для примера матрица тождеств 8 на 8, кодируемая среди четырех рабочих, с двумя столбцами на каждом рабочем, отображениях так:

>> spmd
II = eye(8,'codistributed')
end
Lab 1: 
  This lab stores II(:,1:2).
          LocalPart: [8x2 double]
      Codistributor: [1x1 codistributor1d]
Lab 2: 
  This lab stores II(:,3:4).
          LocalPart: [8x2 double]
      Codistributor: [1x1 codistributor1d]
Lab 3: 
  This lab stores II(:,5:6).
          LocalPart: [8x2 double]
      Codistributor: [1x1 codistributor1d]
Lab 4: 
  This lab stores II(:,7:8).
          LocalPart: [8x2 double]
      Codistributor: [1x1 codistributor1d]

Чтобы увидеть фактические данные в локальном сегменте массива, используйте getLocalPart функция.

Сколько распределяется между каждым работником

При распределении массива N строки, если N равномерно делится на количество работников, MATLAB хранит одинаковое число строк (N/numlabs) на каждом работнике. Когда это число неравномерно делится на количество работников, MATLAB разделяет массив как можно более равномерно.

MATLAB предоставляет свойства объекта codistributor, называемые Dimension и Partition который можно использовать, чтобы определить точное распределение массива. Смотрите раздел Индексация в кодируемый массив для получения дополнительной информации об индексации с кодируемыми массивами.

Распределение других типов данных

Можно распределять массивы любого встроенного типа данных MATLAB, а также числовые массивы, которые являются сложными или разреженными, но не массивами указателей на функцию или типов объектов.

Создание кодового распределенного массива

Вы можете создать codistributed array любым из следующих способов:

  • Секционирование Большого Массива - начните с большого массива, который реплицируется на всех рабочих местах, и разделите его так, чтобы части были распределены между рабочими. Это наиболее полезно, когда у вас достаточно памяти для хранения исходного реплицированного массива.

  • Построение из меньших массивов - начните с меньшего варианта или реплицированных массивов, хранящихся на каждом рабочем месте, и объедините их, чтобы каждый массив стал сегментом большего кодового распределенного массива. Этот метод уменьшает требования к памяти, так как позволяет вам создавать кодовый распределенный массив из небольших частей.

  • Использование функций MATLAB Constructor - Используйте любую из функций конструктора MATLAB, таких как rand или zeros с аргументом объект. Эти функции предлагают быстрое средство построения кодируемого массива любого размера всего за один шаг.

Разбиение больших массивов

Если у вас уже есть большой массив в памяти, который вы хотите, чтобы MATLAB обработал быстрее, можно разделить его на меньшие сегменты и распределить эти сегменты среди всех работников, используя codistributed функция. Каждый рабочий процесс затем имеет массив, который представляет собой часть размера исходного, таким образом сокращая время, необходимое для доступа к данным, локальным для каждого рабочего.

В качестве простого примера следующая строка кода создает реплицированную матрицу 4 на 8 для каждого работника, назначенного переменной A:

spmd, A = [11:18; 21:28; 31:38; 41:48], end
A =
    11    12    13    14    15    16    17    18
    21    22    23    24    25    26    27    28
    31    32    33    34    35    36    37    38
    41    42    43    44    45    46    47    48

В следующей линии используется codistributed функция для создания одной матрицы 4 на 8 D который распределен вдоль второго измерения массива:

spmd
    D = codistributed(A);
    getLocalPart(D)
end

1: Local Part  | 2: Local Part  | 3: Local Part  | 4: Local Part
    11    12   |     13    14   |     15    16   |     17    18
    21    22   |     23    24   |     25    26   |     27    28
    31    32   |     33    34   |     35    36   |     37    38
    41    42   |     43    44   |     45    46   |     47    48

Массивы направленности A и D имеют одинаковый размер (4 на 8). Массивы A существует в полном размере на каждом рабочем месте, в то время как только сегмент массива D существует на каждом рабочем месте.

spmd, size(A), size(D), end

Исследуя переменные в рабочей рабочей области клиента, массив, который кодируется среди работников внутри spmd оператор, является распределенным массивом с точки зрения клиента за пределами spmd оператор. Переменные, которые не кодируются внутри spmd, являются Composites в клиенте вне spmd.

whos
  Name      Size            Bytes  Class 

  A         1x4               613  Composite
  D         4x8               649  distributed

См. codistributed страница с описанием функции для синтаксиса и информации об использовании.

Создание из небольших массивов

codistributed функция менее полезна для уменьшения объема памяти, необходимой для хранения данных, когда вы сначала создаете полный массив в одной рабочей области, а затем разбиваете его на распределенные сегменты. Чтобы сэкономить на памяти, можно сначала создать меньшие части (локальная часть) для каждого рабочего процесса, а затем использовать codistributed.build чтобы объединить их в один массив, который распределен между работниками.

Этот пример создает вариант массива A 4 на 250 для каждого из четырех рабочих процессов, а затем использует codistributor чтобы распределить эти сегменты по четырем рабочим местам, создав массив с кодовым распределением 4 на 1000. Вот вариант массива, A:

spmd
  A = [1:250; 251:500; 501:750; 751:1000] + 250 * (labindex - 1);
end

    WORKER 1             WORKER 2             WORKER 3
  1    2 ... 250 |  251   252 ... 500 |  501   502 ... 750 | etc.
251  252 ... 500 |  501   502 ... 750 |  751   752 ...1000 | etc.
501  502 ... 750 |  751   752 ...1000 | 1001  1002 ...1250 | etc.
751  752 ...1000 | 1001  1002 ...1250 | 1251  1252 ...1500 | etc.
                 |                    |                    |

Теперь объедините эти сегменты в массив, который распределяется по первой размерности (строкам). Массив теперь 16 на 250, с сегментом 4 на 250, проживающим на каждом рабочем месте:

spmd
  D = codistributed.build(A, codistributor1d(1,[4 4 4 4],[16 250]))
end
Lab 1: 
    This lab stores D(1:4,:).
           LocalPart: [4x250 double]
      Codistributor: [1x1 codistributor1d]

whos
  Name       Size             Bytes  Class

  A          1x4                613  Composite
  D         16x250              649  distributed

Можно также использовать реплицированные массивы таким же образом, если вы хотите создать распределенный по коду массив, все сегменты которого были идентичны, начиная с. См. codistributed страница с описанием функции для синтаксиса и информации об использовании.

Использование функций конструктора MATLAB

MATLAB предоставляет несколько функций конструктора массивов, которые можно использовать для создания кодовых распределенных массивов с определенными значениями, размерами и классами. Эти функции работают так же, как и их неразраспределенные аналоги на языке MATLAB, за исключением того, что они распределяют результирующий массив между работниками, используя заданный объект codistributor, codist.

Функции конструктора.  Здесь перечислены кодовые функции конструктора. Используйте codist аргумент (созданный codistributor функция: codist=codistributor()), чтобы указать, по какой размерности распределять массив. Для получения дополнительной информации о синтаксисе и использовании см. отдельные страницы с описанием по этим функциям.

eye(___,codist)
false(___,codist)
Inf(___,codist)
NaN(___,codist)
ones(___,codist)
rand(___,codist)
randi(___,codist)
randn(___,codist)
true(___,codist)
zeros(___,codist)

codistributed.cell(m,n,...,codist)
codistributed.colon(a,d,b)
codistributed.linspace(m,n,...,codist)
codistributed.logspace(m,n,...,codist)
sparse(m,n,codist)
codistributed.speye(m,...,codist)
codistributed.sprand(m,n,density,codist)
codistributed.sprandn(m,n,density,codist)

Локальные массивы

Та часть кодового распределенного массива, которая находится на каждом рабочем месте, является частью большего массива. Каждый рабочий процесс может работать со своим собственным сегментом обычного массива, или он может сделать копию этого сегмента в собственном варианте или частном массиве. Эта локальная копия сегмента кодового распространения массива называется локальным массивом.

Создание локальных массивов из кодируемого массива

The getLocalPart функция копирует сегменты кодированного массива в отдельный массив вариантов. Этот пример делает локальную копию L каждого сегмента распределенных по коду массивов D. Размер L показывает, что он содержит только локальную часть D для каждого работника. Предположим, что вы распределяете массив между четырьмя работниками:

spmd(4)
    A = [1:80; 81:160; 161:240];
    D = codistributed(A);
    size(D)
       L = getLocalPart(D);
    size(L)
end

возвращает на каждом работнике:

3    80
3    20

Каждый рабочий процесс распознает, что кодированный массив D 3 на 80. Однако заметьте, что размер локальной детали, L, 3 на 20 на каждом рабочем, потому что 80 столбцов D распределяются по четырем рабочим.

Создание кодового распределения из локальных массивов

Используйте codistributed.build функция для выполнения обратной операции. Эта функция, описанная в Создании из меньших массивов, объединяет локальные варианты массивов в один массив, распределенный по заданному измерению.

Продолжая предыдущий пример, возьмите локальные массивы вариантов L и объедините их как сегменты, чтобы создать новый кодовый массив X.

spmd
  codist = codistributor1d(2,[20 20 20 20],[3 80]);
  X = codistributed.build(L,codist);
  size(X)
end

возвращает на каждом работнике:

3    80

Получение информации об массиве

MATLAB предлагает несколько функций, которые обеспечивают информацию о любом конкретном массиве. В дополнение к этим стандартным функциям существуют также две функции, которые полезны исключительно с кодированными массивами.

Определение, является ли массив кодовым распространением

iscodistributed функция возвращает логическое 1 (true), если массив входа кодировался, и логический 0 (false) в противном случае. Синтаксис:

spmd, TF = iscodistributed(D), end

где D - любой массив MATLAB.

Определение размерности распределения

Объект codistributor определяет, как разделяется массив и его размерность распределения. Для доступа к codistributor массива используйте getCodistributor функция. Это возвращает два свойства, Dimension и Partition:

spmd, getCodistributor(X), end

     Dimension: 2
     Partition: [20 20 20 20]

The Dimension значение 2 означает массив X распределяется по столбцам (размерность 2); и Partition значение [20 20 20 20] означает, что двадцать столбцов находятся на каждом из четырех рабочих.

Чтобы получить эти свойства программно, верните выход getCodistributor в переменную, затем используйте запись через точку для доступа к каждому свойству:

spmd
    C = getCodistributor(X);
    part = C.Partition
    dim  = C.Dimension
end

Другие функции массива

Другие функции, которые обеспечивают информацию о стандартных массивах, также работают с кодистрибурированными массивами и используют тот же синтаксис.

  • length - Возвращает длину определенной размерности.

  • ndims - Возвращает количество размерностей.

  • numel - Возвращает количество элементов в массиве.

  • size - Возвращает размер каждой размерности.

  • is* - Многие функции, имена которых начинаются с 'is', таких как ischar и issparse.

Изменение размерности распределения

При построении массива вы распределяете части массива по одному из размерностей массива. Изменить направление этого распределения можно на существующем массиве с помощью redistribute функция с другим объектом codistributor.

Создайте массив с кодовым распределением 8 на 16 D случайных значений, распределенных по столбцам на четырех работниках:

spmd
    D = rand(8,16,codistributor());
    size(getLocalPart(D))
end

возвращает на каждом работнике:

8     4

Создайте новый codistributed массив, распределенный по строкам из существующего, уже распределенного по столбцам:

spmd
    X = redistribute(D, codistributor1d(1));
    size(getLocalPart(X))
end

возвращает на каждом работнике:

2    16

Восстановление полного массива

Можно восстановить кодовый распространенный массив в его неограниченную форму, используя gather функция. gather принимает сегменты массива, расположенные на разных рабочих местах, и объединяет их в реплицированный массив на всех рабочих местах или в один массив на одном рабочем месте.

Распределите массив 4 на 10 четырем рабочим по второму измерению:

spmd,  A = [11:20; 21:30; 31:40; 41:50],  end
A =
    11    12    13    14    15    16    17    18    19    20
    21    22    23    24    25    26    27    28    29    30
    31    32    33    34    35    36    37    38    39    40
    41    42    43    44    45    46    47    48    49    50

spmd,  D = codistributed(A),  end


      WORKER 1        WORKER 2      WORKER 3     WORKER 4
    11   12   13  | 14   15   16  |  17   18  |  19    20
    21   22   23  | 24   25   26  |  27   28  |  29    30
    31   32   33  | 34   35   36  |  37   38  |  39    40
    41   42   43  | 44   45   46  |  47   48  |  49    50
                  |               |           |

spmd,  size(getLocalPart(D)),  end
Lab 1: 
    4     3
Lab 2: 
    4     3
Lab 3: 
    4     2
Lab 4: 
    4     2

Восстановите неограниченные сегменты в форме полного массива путем сбора сегментов:

spmd,  X = gather(D),  end
X =
    11    12    13    14    15    16    17    18    19    20
    21    22    23    24    25    26    27    28    29    30
    31    32    33    34    35    36    37    38    39    40
    41    42    43    44    45    46    47    48    49    50

spmd,  size(X),  end
    4    10

Индексация в кодовый распределенный массив

В то время как индексация в неразраспределенный массив довольно проста, кодораспределенные массивы требуют дополнительных факторов. Каждая размерность неразраспределенного массива индексируется в области значений от 1 до конечного индекса, который представлен в MATLAB end ключевое слово. Длина любой размерности может быть легко определена с помощью size или length функция.

С кодированными массивами эти значения не так легко получить. Например, второй сегмент массива (тот, что находится в рабочей области работника 2) имеет стартовый индекс, который зависит от распределения массива. Для массива 200 на 1000 с распределением по умолчанию по столбцам над четырьмя рабочими начальный индекс для работника 2 равен 251. Для массива 1000 на 200, также распределенного по столбцам, этот же индекс будет 51. Что касается конечного индекса, это не задается при помощи end ключевое слово, как end в этом случае относится к концу всего массива; то есть последний индекс конечного сегмента. Длина каждого сегмента также не задается при помощи length или size функций, так как они возвращают только длину всего массива.

Система MATLAB colon оператор и end ключевое слово является двумя базовыми инструментами для индексации в неразраспределенные массивы. Для кодированных массивов MATLAB предоставляет версию colon оператор, вызываемый codistributed.colon. Это на самом деле функция, а не символьный оператор, такой как colon.

Примечание

При использовании массивов для индексации в распределенные по коду массивы для индексации можно использовать только реплицированные или распространенные по коду массивы. Тулбокс не проверяет, чтобы убедиться, что индекс реплицирован, так как это потребует глобальной связи. Поэтому использование неподдерживаемых вариантов (таких как labindex) для индекса в кодовые распределенные массивы могут привести к неожиданным результатам.

Пример: Найти конкретный элемент в кодовом массиве

Предположим, что у вас есть вектор-строка из 1 миллиона элементов, распределенный между несколькими рабочими, и вы хотите найти его число элементов 225,000. То есть необходимо знать, какой рабочий процесс содержит этот элемент, и в какой позиции в локальной части вектора на этом рабочем месте. globalIndices функция обеспечивает корреляцию между локальной и глобальной индексацией кодируемого массива.

D = rand(1,1e6,'distributed'); %Distributed by columns
spmd
    globalInd = globalIndices(D,2);
    pos = find(globalInd == 225e3);
    if ~isempty(pos)
      fprintf(...
      'Element is in position %d on worker %d.\n', pos, labindex);
    end
end

Если вы запускаете этот код в пуле четырех работников, вы получаете этот результат:

Lab 1: 
  Element is in position 225000 on worker 1.

Если вы запускаете этот код в пуле из пяти работников, вы получаете этот результат:

Lab 2: 
  Element is in position 25000 on worker 2.

Заметьте, что если вы используете пул другого размера, элемент попадает в другое место на другом рабочем месте, но для определения местоположения элемента может использоваться тот же код.

2-Dimensional распределения данных

В качестве альтернативы распределению по одной размерности строк или столбцов можно распределить матрицу по блокам, используя '2dbc' или двумерное блочно-циклическое распределение. Вместо сегментов, которые состоят из ряда полных строк или столбцов матрицы, сегменты кодового распределенного массива являются 2-мерными квадратными блоками.

Для примера рассмотрим простую матрицу 8 на 8 с значениями восходящего элемента. Можно создать этот массив в spmd оператор или коммуникационное задание.

spmd
    A = reshape(1:64, 8, 8)
end

Результатом является реплицированный массив:

     1     9    17    25    33    41    49    57

     2    10    18    26    34    42    50    58

     3    11    19    27    35    43    51    59

     4    12    20    28    36    44    52    60

     5    13    21    29    37    45    53    61

     6    14    22    30    38    46    54    62

     7    15    23    31    39    47    55    63

     8    16    24    32    40    48    56    64

Предположим, что вы хотите распределить этот массив между четырьмя рабочими, с блоком 4 на 4 в качестве локальной части на каждом рабочем. В этом случае лабораторная сетка является расположением рабочих 2 на 2, и размер блока представляет собой квадрат из четырех элементов со стороны (то есть каждый блок представляет собой квадрат 4 на 4). С помощью этой информации можно задать объект codistributor:

spmd
    DIST = codistributor2dbc([2 2], 4);
end

Теперь можно использовать этот объект codistributor для распределения исходной матрицы:

spmd
    AA = codistributed(A, DIST)
end

Это распределяет массив между работниками согласно этой схеме:

Если лабораторная сетка не полностью перекрывает размерности кодируемого массива, вы все равно можете использовать '2dbc' распределение, которое является циклическим блоком. В этом случае можно представить, что лабораторная сетка неоднократно накладывается в обеих размерностях, пока не будут включены все исходные элементы матрицы.

Используя ту же исходную матрицу 8 на 8 и лабораторную сетку 2 на 2, рассмотрим размер блока 3 вместо 4, так что квадратные блоки 3 на 3 распределяются между рабочими. Код выглядит следующим образом:

spmd
    DIST = codistributor2dbc([2 2], 3)
    AA = codistributed(A, DIST)
end

Первая «строка» лабораторной сетки распределена между рабочим 1 и рабочим 2, но она содержит только шесть из восьми столбцов исходной матрицы. Поэтому следующие два столбца распределяются между работником 1. Этот процесс продолжается до тех пор, пока не будут распределены все столбцы в первых строках. Затем аналогичный процесс применяется к строкам, когда вы продолжаете вниз по матрице, как показано на следующей схеме распределения:

Схема выше показывает схему, которая требует четырех наложений лабораторной сетки, чтобы вместить всю исходную матрицу. Следующий код показывает полученное распределение данных по каждому из работников.

spmd
    getLocalPart(AA)
end
Lab 1: 
  
  ans =
  
       1     9    17    49    57
       2    10    18    50    58
       3    11    19    51    59
       7    15    23    55    63
       8    16    24    56    64
  
Lab 2: 
  
  ans =
  
      25    33    41
      26    34    42
      27    35    43
      31    39    47
      32    40    48
  
Lab 3: 
  
  ans =
  
       4    12    20    52    60
       5    13    21    53    61
       6    14    22    54    62
  
Lab 4: 
  
  ans =
  
      28    36    44
      29    37    45
      30    38    46

Стоит отметить следующие точки:

  • '2dbc' распределение может не предлагать никакого улучшения эффективности, если размер блока не менее нескольких десятков. Размер блока по умолчанию равен 64.

  • Лабораторная сетка должна быть как можно ближе к квадрату.

  • Не все функции, которые усилены для работы с '1d' codistributed array работает с '2dbc' codistributed arrays.