为何在MATLAB的spmd块中无法按codistributed数组大小索引?
首先,咱们先搞清楚你原来代码报错的核心原因:你误解了spmd块中直接访问distributed数组索引的行为。
当你在spmd里写idx=1:numel(input)时,numel(input)返回的是整个distributed数组的全局总元素数,而不是当前worker本地分片的元素数。比如你说的100元素数组拆成每个worker10个元素的情况,numel(input)会返回100,你的循环会从1跑到100。当循环到11时,当前worker尝试访问input(11)——这个元素属于其他worker的分片,MATLAB会尝试跨worker获取数据,这时候内部的类型转换逻辑出了问题,就抛出了你看到的unsupported data type for conversion: 'codistributed'错误。
你以为idx=1:numel(input)等价于本地分片的索引范围,但实际上,直接用全局索引访问distributed数组时,MATLAB不会自动限制在本地分片,而是会尝试跨节点获取数据,这就是问题所在。
更可靠的解决方案:直接操作本地分片
不管你的distributed数组分片是否均匀,也不管是一维还是多维数组,都可以通过getLocalPart和localIndices来精准处理当前worker负责的分片:
一维数组示例
input = rand([bignum,1],'distributed'); output = zeros([bignum,1],'distributed'); spmd % 获取当前worker的本地分片 localInput = getLocalPart(input); localOutput = zeros(size(localInput), class(localInput)); % 遍历本地分片的每个元素(只用处理自己负责的部分) for idx = 1:numel(localInput) localOutput(idx) = myFunction(localInput(idx)); end % 将计算好的本地分片赋值回全局distributed数组的对应位置 output(localIndices(input)) = localOutput; end
多维数组示例
对于多维distributed数组,localIndices会返回一个cell数组,每个元素对应维度上的本地索引范围,直接用它来定位全局数组的位置即可:
input = rand([bignum, 10],'distributed'); % 2维distributed数组 output = zeros(size(input), 'distributed'); spmd localInput = getLocalPart(input); [localRows, localCols] = size(localInput); localOutput = zeros(localRows, localCols, class(localInput)); % 多维循环遍历本地分片 for i = 1:localRows for j = 1:localCols localOutput(i,j) = myFunction(localInput(i,j)); end end % 获取本地分片对应的全局索引范围 [globalRowRange, globalColRange] = localIndices(input); output(globalRowRange, globalColRange) = localOutput; end
关于drange的补充说明
你提到用drange(1:numel(input))能运行但不满意,这是因为drange会按照默认的分布策略把循环索引分配给各个worker,当你的数组分片和默认分布不匹配时,就会出现worker需要跨节点获取数据的情况,影响效率。而上面的方案是直接操作本地已有的分片,完全避免了跨节点数据传输,效率更高,也适配所有分片情况。
内容的提问来源于stack exchange,提问作者Frank

