exponenta event banner

Работа с распределенными массивами

Как программное обеспечение 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 отображается информация о распределенном по коду массиве, локальной части и распространителе кодов. Например, матрица идентичности 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, а также числовые массивы, которые являются сложными или разреженными, но не массивы дескрипторов функций или типов объектов.

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

Можно создать распределенный массив одним из следующих способов:

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

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

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

Секционирование большего массива

Если у вас уже есть большой массив в памяти, который вы хотите, чтобы 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 чтобы объединить их в единый массив, распределенный по работникам.

В этом примере создается массив вариантов 4 на 250 A для каждого из четырех работников, а затем используется 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)

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

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

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

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.

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

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

spmd, getCodistributor(X), end

     Dimension: 2
     Partition: [20 20 20 20]

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

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

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

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

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

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

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

Примечание

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

Пример: Поиск определенного элемента в распределенном массиве Codistributed

Предположим, что у вас есть вектор строки из 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' codtisted массивы работают на '2dbc' распределенные массивы.