-1

いくつかの計算を実行し、結果をマージするプログラムを作成しました。

マルチスレッドを使用して並列計算を行いました。

マージ結果のフェーズでは、各スレッドはグローバル配列をロックし、個々の部分をそれに追加し、繰り返しをなくすために追加の作業が行われます。

テストしたところ、スレッドの数が増えるとマージのコストが増加することがわかりました。速度は予想外です:

2 スレッド: 40,116,084(us)
6 スレッド:511,791,532(us

) これを変更するにはどうすればよいですか?

--------------------------スラッシュライン ---------------------- -------------------------------

実際、コードは非常に単純で、疑似コードがあります:

typedef my_object{
いいえ。
int カウント;
二重値;
//何か他のもの
} my_object_t;

static my_object_t** global_result_array; //約10,000

static pthread_mutex_t global_lock;

void* thread_function(void* arg){
my_object_t** local_result;
int local_result_number;
int i;
my_object_t* ptr;
for(;;){
if( exit_condition ){ return NULL;}
if( merge_condition){
//ログの開始時点
pthread_mutex_lock( &global_lock);
for( i = local_result_number-1; i>=0 ;i++){
ptr = local_result[ i] ;
if( NULL == global_result_array[ ptr->no] ){
global_result_array[ ptr->no] = ptr; //ステップ 4
}else{
global_result_array[ ptr->no] -> カウント += ptr->カウント; // ステップ 5
global_result_array[ ptr->no] -> 値 += ptr->value; // ステップ 6
}
}
pthread_mutex_unlock( &global_lock); // ログに記録する終了時点
}else{
// 何らかの計算を行い、部分的かつスレッド ローカルな結果、つまり local_result と local_result_number を生成します
}
}
}


以上のように、2スレッドと6スレッドの違いはstep5とstep6で、step5とstep6の実行順序は数億回程度あったと数えています。他は同じです。
したがって、私の見解では、2 つのスレッドまたは 6 つのスレッドを使用しているにもかかわらず、マージ操作は非常に軽く、両方ともロックして排他的にマージする必要があります。
もう一つ驚いたのは、6 スレッドを使用すると、ステップ 4 のコストが急上昇したことです。トータルコストが爆上がりしたのはブーツのせいでした!

ところで: テスト サーバーには 2 つの CPU があり、各 CPU には 4 つのコアがあります。

4

3 に答える 3

1

表示される動作にはさまざまな理由があります。

  1. スレッドが増えるということは、スレッド間のロックとブロック時間が増えることを意味します。あなたの説明から明らかなように、あなたの実装はミューテックスロックなどを使用しています。データ セットの大部分が排他的である場合は、スレッドによる高速化が向上します。

  2. システムにスレッドの数と同じ数のプロセッサ/コアがない限り、それらすべてを同時に実行することはできません。を使用して最大同時実行数を設定できますpthread_setconcurrency

于 2012-10-02T01:22:01.367 に答える
0

コンテキストの切り替えはオーバーヘッドです。したがって、違い。お使いのコンピューターに 6 コアが搭載されている場合は、より高速になります。過度にスレッドのコンテキストスイッチを増やす必要があります。

于 2012-10-02T01:07:55.417 に答える
0

これは、2/6 スレッド間の大きなパフォーマンスの違いです。申し訳ありませんが、このような大きな違いを生み出すには、本当に一生懸命努力する必要があります。あなたは成功したようです:((

他の人が指摘しているように、1 つのデータ セットで複数のスレッドを使用する価値があるのは、スレッド間通信 (ロックなど) に費やされる時間が同時操作によって得られる時間よりも短い場合のみです。

たとえば、連続して小さなデータ セクションをマージしていることがわかった場合 (たとえば、マージ ソートを使用)、スレッド間通信とキャッシュ スラッシングに費やされる時間を効果的に最適化しています。これが、データが L1 キャッシュのサイズよりも小さいチャンクに分割されると、インプレース ソートでマルチスレッド マージ ソートが頻繁に開始される理由です。

「各スレッドはグローバル配列をロックします」-これを行わないようにしてください。大規模なデータ構造を長期間ロックしたり、短期間連続してロックしたりすることは、非常に悪い計画です。グローバルを一度ロックすると、スレッドがシリアル化され、スレッド間通信が多すぎるスレッドが 1 つ生成されます。継続的にロック/解放すると、スレッド間通信が多すぎるスレッドが 1 つ生成されます。

操作が非常に短くなり、リターンが無用に減少した場合は、それらの操作を 1 つのスレッドにキューイングして、それ自体でジョブを終了させることをお勧めします。

多くの場合、ロックは過度に使用されたり、誤用されたりします。ポインターをキューなどにプッシュ/ポップするのにかかる時間よりも長く何かをロックしていることに気付いた場合、私はぎくしゃくし始めます..

コード、さらに重要なことにデータを見て分析しないと、(どちらも複雑だと思います)、直接的なアドバイスをすることは困難です:(

于 2012-10-02T11:03:20.107 に答える