4

マトリックスの作成には同時ハッシュマップを使用しました。インデックスの範囲は100kです。40個のスレッドを作成しました。各スレッドは、マトリックスのこれらの要素にアクセスし、それに変更して、次のようにマトリックスに書き戻します。

ConcurrentHashMap<Integer, ArrayList<Double>> matrix = 
    new ConcurrentHashMap<Integer, ArrayList<Double>>(25);

for (Entry(Integer,ArrayList<Double>)) entry: matrix.entrySet())
    upDateEntriesOfValue(entry.getValue());     

スレッドセーフではありませんでした。値がnullとして返されることが多く、プログラムがクラッシュします。スレッドセーフにする他の方法はありますか?またはこれはスレッドセーフであり、他の場所にバグがあります。1つは、プログラムがシングルスレッドモードでクラッシュしないことです。

4

3 に答える 3

11

iterator確かにスレッドセーフですConcurrentHashMap

しかし、コードでスレッドセーフではないのは、ArrayList<Double>更新しているように見えることです。問題は、このデータ構造に起因する可能性があります。

ニーズに合わせた同時データ構造を使用することをお勧めします。

于 2012-08-03T07:33:57.020 に答える
2

行列にマップを使用することは実際には非効率的であり、それを使用した方法では、スパース配列を特にうまくサポートすることすらできません。

各行(またはそれが適切な場合は列)をロックするdouble [] []を使用することをお勧めします。マトリックスが十分に小さい場合は、CPUを1つだけ使用する方がよい場合があります。これにより、オーバーヘッドを大幅に節約できます。

コアよりも多くのスレッドを作成しないことをお勧めします。CPUを集中的に使用するタスクの場合、より多くのスレッドを使用すると、速くなるのではなく、遅くなる可能性があります。

マトリックスは最大で100k*50です

編集:実行している操作に応じて、最初に短いディメンションを使用して、異なるスレッドで各長いディメンションを効率的に処理できるようにします。

例えば

double[][] matrix = new double[50][100*1000];
for(int i=0;i<matrix.length;i++) {
   final double[] line = matrix[i];
   executorService.submit(new Runnable() {
       public void run() {
          synchronized(line) {
              processOneLine(line);
          }
       }
   });
}

これにより、データ構造を共有しないため、すべてのスレッドを同時に実行できます。また、メモリ内で連続しており、可能な限り効率的に格納されるため、各doubleに効率的にアクセスできます。つまり、100Kダブルは約800KBを使用しますが、List<Double>2800KBを使用し、各値をメモリ内にランダムに配置できるため、キャッシュの動作がはるかに困難になります。

ありがとうございますが、実際には合計80コアあります

80コアを効率的に使用するには、長い行を2つまたは4つに分割して、すべてのコアをビジー状態に保つか、一度に複数の操作を実行する方法を見つけることができます。

于 2012-08-03T07:41:47.930 に答える
1

ConcurrentHashMapマップへのアクセスに対してスレッドセーフになりますが、複数のスレッドが同じリストインスタンスで同時に動作できる場合は、提供さListsれる必要があるため、変更中にしばらく使用してください。thread-safethread-safe list

あなたの場合、作業 ConcurrentHashMapはトレッドセーフですが、スレッドがArrayListこれに行くときはそうではないsynchronizedため、複数のスレッドが同時にアクセスでき、スレッドセーフではなくなります。synchronized blockリスト内の変更を実行している場所で使用できます

于 2012-08-03T07:37:17.513 に答える