主要内容

使用协同分布数组

如何MATLAB软件分配数组

当你把一个数组分配给一些工作者时,MATLAB®软件将阵列划分为多个段,并将其中的一个段分配给每个工作人员。您可以水平地划分二维数组,将原始数组的列分配给不同的工作人员,也可以垂直地分配行。一个N维的数组可以沿着它的任何一个维进行分区。您可以在数组构造函数命令中指定要对数组的哪个维度进行分区。

例如,要将一个80 × 1000的数组分配给4个worker,可以按列划分,给每个worker一个80 × 250的段,或者按行划分,给每个worker一个20 × 1000的段。如果数组维数不能均匀地除以工作人员的数量,MATLAB会尽可能均匀地对它进行分区。

下面的示例创建一个80 × 1000的复制数组并将其赋值给变量一个.这样,每个工作人员在自己的工作区中创建一个相同的数组,并将其赋值给variable一个,在那里一个对那个工人来说是本地的第二个命令分发一个,创建一个80 × 1000的数组D这涵盖了所有四名工人。Worker 1存储列1到250,Worker 2存储列251到500,以此类推。默认分布是由最后一个非单例维度决定的,因此,在本例中是一个2维数组。

spmd A = 0 (80, 1000);D = codistributed(A) end实验1:这个实验室存储D(:,1:250)。实验2:这个实验室储存D(:,251:500)。实验3:这个实验室储存D(:,501:750)。实验4:这个实验室储存D(:,751:1000)。

每个worker都可以访问数组的所有段。访问本地段要比访问远程段快,因为远程段需要在工作者之间发送和接收数据,因此需要更多的时间。

如何MATLAB显示一个协分布数组

对于每个worker, MATLAB并行命令窗口显示关于协分布数组、局部部分和协分布器的信息。例如,一个8 × 8的单位矩阵在4个工人之间协分布,每个工人有两列,如下所示:

实验1:这个实验室存储II(:,1:2)。LocalPart: [8x2 double] Codistributor: [1x1 codistributor1d] Lab 2:这个实验室存储II(:,3:4)。LocalPart: [8x2 double] Codistributor: [1x1 codistributor1d] Lab 3:这个实验室存储II(:,5:6)。LocalPart: [8x2 double] Codistributor: [1x1 codistributor1d] Lab 4:此实验室存储II(:,7:8)。LocalPart: [8x2 double] Codistributor: [1x1 codistributor1d]

要查看数组的本地段中的实际数据,请使用getLocalPart函数。

每个工人分得多少

在分配数组时N行,如果N被工作人员数整除,MATLAB存储相同的行数(N / numlabs)。当这个数字不能被工作人员的数量均匀整除时,MATLAB会尽可能均匀地对数组进行分区。

MATLAB提供了协分布器对象的属性调用分区可以用来确定数组的准确分布。看到索引到Codistributed数组有关使用协分布数组进行索引的更多信息。

其他数据类型的分布

可以分布任何MATLAB内置数据类型的数组,也可以分布复杂或稀疏的数字数组,但不能分布函数句柄或对象类型的数组。

创建Codistributed Array

你可以通过以下任何一种方式创建一个codistributed数组:

  • 对较大的阵列进行分区-以一个复制到所有worker上的大数组开始,并对它进行分区,以便各个块分布在各个worker上。当您有足够的内存来存储初始复制数组时,这是非常有用的。

  • 从更小的数组构建-从存储在每个worker上的较小的变体或复制数组开始,并将它们组合,使每个数组成为更大的协分布数组的一个片段。这种方法减少了内存需求,因为它允许您从较小的块构建一个协同分布数组。

  • MATLAB构造函数的使用-使用任何MATLAB构造函数兰德0使用协分配器对象参数。这些函数提供了一种只需一步就可以构造任意大小的协分布数组的快速方法。

对较大的阵列进行分区

如果内存中已经有一个大数组,想让MATLAB更快地处理它,可以将它划分为更小的段,并将这些段分配给使用codistributed函数。然后,每个worker都有一个数组,这个数组的大小是原始数据的一小部分,这样就减少了访问每个worker本地数据所需的时间。

作为一个简单的示例,下面的代码行在分配给变量的每个worker上创建一个4乘8复制的矩阵一个

spmd, A = [11:18;21:28;31:38;41:48],结束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它沿着数组的第2维分布:

spmd D = codistribute (A);getLocalPart (D)结束1:本地部分| 2:本地部分| 3:本地部分| 4:本地部分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

数组一个D大小相同(4 × 8)。数组一个在每个worker上以其完整的大小存在,而只有一个数组段D存在于每个工人身上。

尺寸(A),尺寸(D),结束

检查客户端工作空间中的变量,这个数组是在一个spmd语句,从客户端的角度来看,是一个分布式数组spmd声明。在spmd内部不是协同分布的变量是spmd外部客户端的composite。

谁的名字大小字节类1×8 x4 613复合D 649分布

看到codistributed函数参考页的语法和用法信息。

从更小的数组构建

codistributed当您第一次在一个工作空间中构造完整的数组,然后将其划分为分布式段时,函数在减少存储数据所需的内存量方面用处不大。为了节省内存,可以先在每个worker上构造较小的部分(本地部分),然后使用codistributed.build将它们组合成一个分布在各个工作人员之间的单一数组。

这个例子在每个工人上创建一个4 × 250的变量数组a,然后使用codistributor要将这些片段分布到四个worker中,需要创建一个4 × 1000的协分布数组。这是变量数组,一个

spmd A = [1:40 0;251:500;501:750;+ 250 * (labindex - 1);WORKER 1 WORKER 2 WORKER 3 1 2…250 | 251 252…500 | 501 502…750 |等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,每个worker上都有一个4乘250的段:

spmd D =共分布。build(A, codistributor1d(1,[4 4 4],[16 250])) end Lab 1:这个实验室存储D(1:4,:)。LocalPart: [4x250 double] Codistributor: [1x1 codistributor1d] whoos Name Size Bytes Class A 1x4 613 Composite D 16x250 649 distributed . LocalPart: [4x250 double] Codistributor: [1x1 codistributor1d] whoos Name Size Bytes Class A 1x4 613 Composite D 16x250 649 distributed

如果您想要创建一个段一开始就完全相同的协分布数组,您也可以以同样的方式使用复制数组。看到codistributed函数参考页的语法和用法信息。

使用MATLAB构造器函数

MATLAB提供了几个数组构造函数,您可以使用它们来构建特定值、大小和类的协同分布数组。这些函数的操作方式与MATLAB语言中的非分布式函数相同,不同之处在于它们使用指定的协分发器对象将结果数组分发给各个工作人员,codist

构造函数的功能。这里列出了协作分布的构造函数。使用codist参数(由codistributor功能:codist = codistributor ()),以指定将数组分布在哪个维度上。有关这些函数的进一步语法和用法信息,请参阅各个参考页面。

眼睛(codist ___)(codist ___)(codist ___)(codist ___)(codist ___)兰德(codist ___)兰迪(codist ___)randn(codist ___)真正的(codist ___)0(codist ___)codistributed.cell(codist m, n,…)codistributed.coloncodistributed (a, d, b)。linspace(m, n,…,codist) codistributed。logspace(codist m, n,…)稀疏的(m, n, codist)codistributed.speye(codist m,…)codistributed.sprand(m, n,密度,codist)codistributed.sprandn(m, n,密度,codist)

本地数组

协同分布数组中驻留在每个worker上的那部分是一个更大数组的一部分。每个worker可以在公共数组的自己的段上工作,也可以在自己的变体或私有数组中复制该段。这个协分布数组段的本地副本称为本地数组

从协分布阵列创建本地阵列

getLocalPart函数将协分布数组的段复制到单独的变体数组。本示例生成一个本地副本l共分布阵列每段的D.的大小l表示它只包含局部的部分D为每一个工人。假设你将一个数组分配给四个worker:

spmd(4) A = [1:20 0;81:160;161:240];D = codistributed(一个);size(D) L = getLocalPart(D);大小(L)

每个工人的回报:

3 80 3 20

每个工作人员都能识别出协作分布的数组D3 -是- 80。但是,请注意局部部分的大小,l,每个工人是3乘20,因为80列D分配给四名工人。

从本地数组创建codistribute

使用codistributed.build函数执行反向操作。这个函数,在从更小的数组构建,将本地变量数组组合成沿指定维度分布的单个数组。

继续前面的示例,使用本地变量数组l并将它们组合成段来构建一个新的协同分布数组X

SPMD codist = codistributor1d(2,[20 20 20 20],[3 80]);X = codistributed.build (L, codist);大小(X)

每个工人的回报:

3 80

获取Array信息

MATLAB提供了几个函数来提供任何特定数组的信息。除了这些标准函数外,还有两个函数只对协分布数组有用。

判断阵列是否为协分布

iscodistributed函数返回逻辑的1真正的),如果输入数组是协分布的,且符合逻辑0否则)。语法

spmd, TF = iscodistributed(D),结束

在哪里D是任何MATLAB数组。

确定分布的维度

协分发器对象决定数组的分区方式及其分布的维数。要访问数组的协分布器,请使用getCodistributor函数。它返回两个属性,分区

spmd, getCodistributor(X), end Dimension: 2 Partition: [20 20 20 20]

的价值2意味着数组X按列分布(维度2);和分区的价值[20 20 20 20]意味着在四个工作人员的每一个上都有20列。

要以编程方式获取这些属性,请返回getCodistributor,然后使用点表示法访问每个属性:

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

其他数组函数

其他提供有关标准数组信息的函数也可以在协作分布式数组上工作,并使用相同的语法。

  • 长度-返回指定尺寸的长度。

  • ndims-返回维度的数量。

  • 元素个数-返回数组中元素的个数。

  • 大小-返回每个维度的大小。

  • 是*-许多函数的名称以“是”,如ischarissparse

改变分布的维度

在构造数组时,将数组的各个部分沿数组的一个维分布。属性可以在现有数组上更改此分发的方向重新分配函数使用不同的协分发器对象。

构造一个8乘16的共分布阵列D在四个工人上按列分布的随机值:

spmd D = rand(8,16,codistributor());大小(getLocalPart (D))

每个工人的回报:

8 4

从现有的按列分布的数组中创建一个新的按行分布的协分布数组:

spmd X = redistributor1d (D, codistributor1d(1));大小(getLocalPart (X))

每个工人的回报:

2 16

恢复全阵列

控件可以将协分布数组恢复为非分布式形式收集函数。收集获取驻留在不同worker上的数组片段,并将它们组合到所有worker上的复制数组中,或组合到一个worker上的单个数组中。

将一个4 × 10的数组分配给第2维的4个工人:

spmd, A = [11:20;晚上9;31:40;41:50],结束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结束职工1工人2工人3职工4 11 12 13 | 14 15 16岁| | 19 20 21日22日23日| 24日25日26日| 27 28 | 29 30 31 32 33 | 34 35 36 | 37 38 43 | | 39 40 41 42 44 45 46 | 47 48 | 49 50 | | | spmd,大小(getLocalPart (D)),结束实验室1:4 3实验室2:4 3实验室3:4 2实验室4:2

通过收集片段,将未分布的片段恢复到完整的数组形式:

spmd, X =收集(D), 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大小(X),结束4 10

索引到Codistributed数组

虽然为非分布式数组建立索引非常简单,但协同分布式数组需要额外的注意事项。非分布式数组的每个维度都在1到最终下标的范围内进行索引,在MATLAB中表示为结束关键字。任何尺寸的长度都可以很容易地使用大小长度函数。

使用协分布数组,这些值就不那么容易获得了。例如,数组的第二段(它驻留在worker 2的工作区中)的起始索引取决于数组的分布。对于200 × 1000的数组,默认分布是由超过4个worker的列组成,worker 2上的起始索引是251。对于同样按列分布的1000 × 200数组,同样的索引是51。至于结束索引,这不是通过使用结束关键字,结束在本例中是指整个数组的结尾;也就是最后一段的最后一个下标。每个线段的长度也不是用长度大小函数,因为它们只返回整个数组的长度。

MATLAB结肠操作员和结束关键字是索引非分布式数组的两个基本工具。对于共分布数组,MATLAB提供了一个版本的结肠运营商,叫做codistributed.colon.这实际上是一个函数,而不是符号运算符结肠

请注意

当使用数组索引到协作分布数组时,只能使用复制或协作分布数组进行索引。工具箱不进行检查以确保索引被复制,因为这将需要全局通信。因此,使用不受支持的变体(例如金宝applabindex)索引到协作分布数组可能会产生意外结果。

示例:在Codistributed数组中查找特定元素

假设您有一个由100万个元素组成的行向量,分布在几个worker中,您想要定位它的元素号为225,000。也就是说,你想知道什么worker包含这个元素,在这个worker上的向量的局部位置。的globalIndices函数提供了协分布数组的局部索引和全局索引之间的关联。

D =兰德(1,1 e6,“分布式”);%分布的列spmd globalInd = globalIndices(D,2);pos = find(globalInd == 225e3);如果~ isempty (pos)流(…'元素在worker %d的位置%d。\ n”、pos、labindex);结束结束

如果你在一个有四个工人的池上运行这段代码,你会得到这样的结果:

实验1:元件在工人1的225000位置。

如果你在一个有5个工人的池中运行这段代码,你会得到这样的结果:

实验2:元件在工人2的25000位置。

注意,如果使用不同大小的池,元素最终会在不同的worker上的不同位置,但可以使用相同的代码来定位元素。

二维分布

作为按行或列的一维分布的替代方法,您可以使用块来分布矩阵“2 dbc”或者二维块循环分布。不是由矩阵的许多完整行或列组成的线段,协分布数组的线段是二维正方形块。

例如,考虑一个简单的8 × 8矩阵,其元素值是升序的。您可以在spmd陈述或沟通工作。

spmd A =重塑(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个worker,每个worker的局部部分是一个4乘4的块。在这种情况下,实验室的网格是工人的2 × 2排列,块的大小是一面由4个元素组成的正方形(即,每个块是4 × 4的正方形)。有了这些信息,你可以定义协分发器对象:

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

现在你可以使用这个协分配器对象来分配原始矩阵:

spmd AA = codistributed(A, DIST) end

这将根据以下方案将数组分配给工人:

如果实验室网格没有完全覆盖协同分布阵列的尺寸,您仍然可以使用“2 dbc”分布,这是块循环。在这种情况下,您可以想象实验室网格在两个维度上重复叠加,直到包含所有原始矩阵元素。

使用相同的原始8 × 8矩阵和2 × 2实验室网格,考虑块大小为3而不是4,这样3 × 3的正方形块就会分布在工人中。代码是这样的:

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

实验网格的第一行是分配给工人1和工人2的,但它只包含原始矩阵的八列中的六列。因此,接下来的两列分配给worker 1。这个过程将继续进行,直到第一行中的所有列都被分布。然后一个类似的过程适用于行,当你继续进行矩阵,如下所示的分布方案:

上面的图表显示了一个方案,它需要四个实验室网格的叠加来容纳整个原始矩阵。下面的代码显示了将数据分配给每个工作人员的结果。

spmd getLocalPart (AA)结束
实验室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实验室2:ans = 25 33 41 26 34 42 27 35 43 31 39 47 32 40 48实验室3:ans = 4 12 20 52 60 5 13 21 53 61 6 14 22 54 62实验室4:ans = 28 36 44 29 37 45 30 38 46

以下几点值得注意:

  • “2 dbc”分发可能不会提供任何性能增强,除非块大小至少是几十个。默认的块大小是64。

  • 实验室的网格应该尽可能接近正方形。

  • 并不是所有的功能都增强了“一维”协同分布数组的工作“2 dbc”codistributed数组。