並列配列を使用できるのはいつですか?


14

私は「並列配列」またはリストと呼んでいるものを使用するコード(新しいコード)を実行しています。つまり、関連データを含む2つの配列があり、配列内の位置(インデックス)によってリンクされています。

私はこれを混乱させ、あらゆる種類のエラーを起こしやすいと考えています。私が通常提案する解決策は、CompanyCompanyIdおよびCompanyNameフィールドで呼び出されるオブジェクトを作成することです。

非常に現実的な例:

List<string> companyNames;
List<int> companyIds;

//...They get populated somewhere and we then process

for(var i=0; i<companyNames.Count; i++)
{
    UpdateCompanyName(companyIds[i],companyNames[i]);
}

これらの並列配列は悪い習慣と見なされていますか?


9
Fortranを記述できない言語が発明されていないことをさらに証明してください。
アンディマンゴー

3
(リンクリストではなく、連続した配列が必要ですが)このようなことを行うと(非常に重要な)キャッシュの利点があります。ただし、これはあなたのケースには当てはまらないようです。パフォーマンスが重要なコードを作成しているようには見えません。
デレクエルキンズは、

2
@DerekElkins ...興味深いことに、これがFortranコードと比較されるコメントの後に続きます。Fortranの初期のバージョンはユーザー定義の構造をサポートしていませんでしたが、追加された後でも慣用的なFortranコードは構造の配列ではなくプロパティの複数の配列を使用します。そして、これは、Fortranが最速の言語であるとしばしば考えられる理由の一部として信じられています。
ジュール

3
この質問に接する思考:多くの関数型言語は、そのようなリストでの作業を積極的に奨励しています。それらには、通常zipと呼ばれる、タプルのリストに変換する関数があります。コードはC#のようになります。C#の最新バージョンでは、ファーストクラスのタプルのサポートが追加されています。したがって、リストを自動的に便利な構造にすることができるzip関数をどこかに追加したのだろうか?
ジュール

4
まあ、2つの配列を意図的に使用する理由は時々ありますが、すべての場合の99%でこれを見て、唯一の理由は元の作者が抱きしめるデータ構造を導入することでした。
Doc Brown

回答:


23

誰かがparrel配列を使用する理由は次のとおりです。

  1. クラスまたは構造体をサポートしない言語で
  2. 個々のスレッドが列の1つのみを変更しているときにスレッドのロックを回避するには
  3. 永続化メソッドがこれらのものを個別に保存することを強制し、それらを再構成する場合
  4. 構造がパディングされている場合、それらはより少ないメモリを消費できます。(C#のこれらのデータ型には適用されません)
  5. CPUキャッシュを効率的に使用するためにデータの一部を近づける必要がある場合(上記のコードでは役に立たないでしょう)。
  6. 単一命令複数データ(SIMD)命令コードの使用。(このコード、または文字列にはまったく適用されません)

この場合、これを行う説得力のある理由は見当たりません...そして、上記のすべてにもっと良いオプションがあるか、高級言語ではあまり有用ではありません。


3
構造がパディングされている場合は、メモリの消費も少なくなります。インテリジェントに割り当てられたいくつかの大きな配列は、構造体の配列よりも少ないメモリを消費できます。
フランクヒルマン

4
4. CPUキャッシュを効率的に使用するために、データの一部を近づけておく必要がある場合。(まれな場合に必要です。)
Blrfl

@Frank Hileman、Whilie TheCatWhispererの答えは完全に正しいと思います。実際、あなたのコメントがこのアプローチを選択する最も良い理由です。メモリ消費が重要な場合、特に多数が使用されている場合、構造体のパディングのメモリオーバーヘッドが大きくなる可能性があります。
ウラジミールストキッチ

答えにあなたの提案を追加
-TheCatWhisperer

再(2)、どうですか?構造体の単一の配列とフィールドごとのロックを使用してプログラムを作成できます。複数の配列と配列ごとのロックを使用してプログラムを作成するのと同じくらい簡単です。
ソロモンスロー

7

私は並列配列を使用した罪を犯しました。時には、構造を抽象化する方法を考えたくないほど、構造に興味があります。抽象化はリファクタリングが少し難しくなる可能性があるため、本当に必要なものを証明するまで、抽象化をすぐに開始することをためらいます。

ただし、その時点では、詳細を抽象化するためにリファクタリングを検討する価値があります。多くの場合、私がそれを行うことに消極的である最大の理由は、良い名前を考えるのが難しいことであることが判明します。

並列配列を抽象化する良い方法が見つかれば、それを毎回行ってください。しかし、触ることを拒否して自分を麻痺させないでください。時々、少し汚いコードが素晴らしいコードへの最良の足がかりです。


6

このパターンは構造の配列とは対照的に)配列の構造とも呼ばれ、コードをベクトル化するときに非常に役立ちます。単一の構造で実行される計算を記述してビットをベクトル化するのではなく、SSE組み込み関数を除き、1つではなく4つの構造で実行されるように、通常どおり計算を記述します。これは通常、より簡単で、ほとんど常に高速です。SoA形式はこれを非常に自然なものにします。また、アライメントが改善され、SSEメモリ操作が高速になります。


はい、このアプローチはGPUで機械学習を行うときに使用されます。多くの別々の例のフィールドを引き離し、各フィールドのすべての値を別々のテンソルにパックし、それらのテンソルを渡してバルクで計算して予測リストを作成するのが慣例です。
モニカの
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.