Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

parfor ループ内の変数のトラブルシューティング

parfor ループの変数が連続的に増加する整数であることの確認

parfor ループ内のループ変数は、連続的に増加する整数でなければなりません。このため、次の例はエラーを返します。

parfor i = 0:0.2:1      % not integers
parfor j = 1:2:11       % not consecutive
parfor k = 12:-1:1      % not increasing
ループ変数を有効な範囲に変換することで、これらのエラーを修正できます。たとえば、非整数の例を次のように修正できます。
iValues = 0:0.2:1;
parfor idx = 1:numel(iValues)
    i = iValues(idx);
    ...
end

parfor ループでのオーバーフローの回避

MATLAB®parfor ループ変数のオーバーフローする可能性を検出すると、エラーを報告します。

オーバーフロー条件解決法

parfor ループの範囲の長さがループ変数の型の最大値を超えている。

以下で、length(-128:127)>maxint('int8') であるため、MATLAB はエラーを報告します。

parfor idx=int8(-128:127)
    idx;
end

より大きなデータ型を parfor ループ変数に使用します。計算で元のデータ型を保持する場合は、parfor ループ内で parfor ループ変数を変換します。

parfor idx=-128:127
    int8(idx);
end

parfor ループの範囲の初期値が、ループ変数の型の最小値に等しい。

以下で、0=intmin('uint32') であるため、MATLAB はエラーを報告します。

parfor idx=uint32(0:1)
    idx;
end

  • 前述の解決策と同じように、より低い最小値をもつより大きなデータ型を使用します。

  • 値の範囲をインクリメントします。以下に例を示します。

    parfor idx=uint32(0:1)+1
        idx-1;
    end

parfor ループ内の変数分類の問題の解決

MATLAB が parfor ループ内の名前を変数として認識すると、その変数は次の表に示す複数のカテゴリのいずれかに分類されます。変数が一意に分類され、カテゴリ要件を満たすことを確認してください。要件に違反する parfor ループはエラーを返します。

分類説明
ループ変数ループ インデックス
スライス化された変数そのセグメントがループの異なる反復で演算される配列
ブロードキャスト変数ループの前に定義される変数。その値はループ内に必要ですがループ内で割り当てられることはありません。
リダクション変数ループの反復を通して値を累積する変数。反復の順序は考慮されません。
一時変数ループ内で作成される変数。ループ外ではアクセスできません。

使用している変数を確認するには、コード フラグメントを調べます。表内のすべての変数分類がこのコードに示されています。

変数分類の問題が生じた場合は、parfor ループの本体を関数に変換するさらに難しい方法を用いる前に、以下の方法を検討してください。

  • 入れ子にされた for ループを使用して、スライス化された配列にインデックスを付ける場合、parfor ループ内の他の場所でその配列を使用することはできません。左側のコードは機能しません。A がスライス化されており、入れ子にされた for ループ内でインデックスが付けられているためです。右側のコードは機能します。入れ子にされたループの外側で vA に代入されているためです。1 行全体を計算してから、スライス化された出力への代入を一度に実行できます。

    無効有効
    A = zeros(4, 10);
    parfor i = 1:4
        for j = 1:10
            A(i, j) = i + j;
        end
        disp(A(i, 1))
    end
    A = zeros(4, 10);
    parfor i = 1:4
        v = zeros(1, 10);
        for j = 1:10
            v(j) = i + j;
        end
        disp(v(1))
        A(i, :) = v;
    end

  • 左側のコードは機能しません。parfor 内の変数 x を分類できないためです。この変数が分類できない理由は、x の異なる部分への代入が複数あるためです。したがって、parfor はループの反復間に依存関係があるかどうかを判定できません。右側のコードは、x の値を完全に上書きしているため機能します。これで parfor は、x が一時変数であると明確に判定できます。

    無効有効
    parfor idx = 1:10
        x(1) = 7;
        x(2) = 8;
        out(idx) = sum(x);
    end
    parfor idx = 1:10
        x = [7, 8];
        out(idx) = sum(x);
    end

  • 次の例では、構造体配列のフィールドをスライス化する方法を説明します。詳細については、struct を参照してください。左側のコードは機能しません。parfor 内の変数 a を分類できないためです。この変数を分類できないのは、インデックス付けの形式が、スライス化された変数では無効なためです。a のフィールド x が正しくスライス化されているように見えますが、第 1 レベルのインデックス付けはスライス化されたインデックス付け操作ではありません。右側のコードは正しく機能します。struct のフィールドを別の変数 tmpx に抽出しているためです。これで parfor は、この変数がスライス化されていることを正しく判定できます。通常、struct のフィールドやオブジェクトのプロパティを、スライス化された入力変数や出力変数として parfor 内で使用することはできません。

    無効有効
    a.x = [];
    parfor idx = 1:10
        a.x(idx) = 7;
    end
    tmpx = [];
    parfor idx = 1:10
        tmpx(idx) = 7;
    end
    a.x = tmpx;

parfor ループの構造体配列

一時変数としての構造体の作成

ドット表記の代入を使用して parfor ループ内に構造体を作成することはできません。左側のコードでは、ループ内の両方の行で分類エラーが発生します。右側のコードでは、回避策として関数 struct を使用することで、ループ内または最初のフィールド内に構造体を作成できます。

無効有効
parfor i = 1:4
    temp.myfield1 = rand();
    temp.myfield2 = i;
end
parfor i = 1:4
    temp = struct();
    temp.myfield1 = rand();
    temp.myfield2 = i;
end
parfor i = 1:4
    temp = struct('myfield1',rand(),'myfield2',i);
end

構造体フィールドのスライス化

構造体フィールドを、スライス化された "入力または出力" 配列として parfor ループ内で使用することはできません。つまり、ループ変数を使用して、構造体フィールドの要素にインデックスを付けることはできません。左側のコードでは、インデックス付けが原因でループ内の両方の行に分類エラーが発生します。右側のコードでは、スライス化された出力を回避するために、スライス化された別々の配列をループ内で使用します。そのうえで、ループの完了後に構造体フィールドを割り当てます。

無効有効
parfor i = 1:4
    outputData.outArray1(i) = 1/i;
    outputData.outArray2(i) = i^2;
end
parfor i = 1:4
    outArray1(i) = 1/i;
    outArray2(i) = i^2;
end
outputData = struct('outArray1',outArray1,'outArray2',outArray2);

スライス化された入力の問題を回避するには、ループの前に構造体フィールドを別の配列に割り当てます。この新しい配列はスライス化された入力に使用できます。

inArray1 = inputData.inArray1;
inArray2 = inputData.inArray2;
parfor i = 1:4
    temp1 = inArray1(i);
    temp2 = inArray2(i);
end

parfor ループ本体から関数への変換

他のすべてが失敗した場合でも、parfor ループ本体を関数に変換することにより、parfor ループでの変数分類の問題を通常は解決できます。左側のコードでは、コード アナライザーが変数 y の問題にフラグを設定しますが、この問題を解決することはできません。右側のコードでは、parfor ループ本体を関数に変換することでこの問題が解決されます。

無効有効
function parfor_loop_body_bad
    data = rand(5,5);
    means = zeros(1,5);
    parfor i = 1:5
        % Code Analyzer flags problem 
        % with variable y below  
        y.mean = mean(data(:,i));
        means(i) = y.mean;
    end
    disp(means);
end
function parfor_loop_body_good
    data = rand(5,5);
    means = zeros(1,5);
    parfor i = 1:5
        % Call a function instead
        means(i) = computeMeans(data(:,i));
    end
    disp(means);
end

% This function now contains the body
% of the parfor-loop
function means = computeMeans(data)
    y.mean = mean(data);
    means = y.mean;
end
Starting parallel pool (parpool) using the 'local' profile ... connected to 4 workers.
    0.6786    0.5691    0.6742    0.6462    0.6307

明確な変数名

parfor ループ内の変数として MATLAB で明確に識別できない名前を使用すると、関数を参照しているものと解析時に想定されます。その上で、実行に際して関数が見つからないと、MATLAB でエラーが発生します変数名を参照してください。たとえば、次のコードでは、f(5)f という配列の 5 番目の要素を参照しているか、または引数 5 をもつ f という関数を参照しているかのいずれかです。f がコード内で変数として明確に定義されていない場合、MATLAB ではコード実行時にパスで関数 f を検索します。

parfor i = 1:n
    ...
    a = f(5);
    ...
end

透過的な parfor ループ

parfor ループ本体は "透過的" でなければなりません。つまり、変数への参照はすべてコードのテキストにおいて "可視" でなければなりません。透過性の詳細については、parfor ループまたは spmd ステートメント内での透過性の確保を参照してください。

グローバル変数および永続変数

parfor ループの本体には、global または persistent の変数宣言を含めることができません。

関連するトピック