-1

問題を説明するためにいくつかの疑似コードを使用してここに要約したプロジェクトがあります。コンパイラの問題はなく、boost または pthreads を使用しているかどうかにかかわらず、コードは適切にコンパイルされます。これは、問題を説明するために設計された疑似コードであり、直接コンパイルできないことに注意してください。

私が抱えている問題は、マルチスレッド関数の場合、for/while ループなどのシリアル プログラミングを使用して同じ関数を実行した場合よりも、メモリ使用量と処理時間が常に長くなることです。

これは、私が直面している問題の簡略版です。

class aproject(){

public:

typedef struct
{
char** somedata;
double output,fitness;
}entity;

entity **entity_array;

int whichthread,numthreads;
pthread_mutex_t mutexdata;



aproject(){
numthreads = 100;
*entity_array=new entity[numthreads];
for(int i;i<numthreads;i++){
entity_array[i]->somedata[i] = new char[100];
}

/*.....more memory allocations for entity_array.......*/
this->initdata();
this->eval_thread();

}
void initdata(){
/**put zeros and ones in entity_array**/

}
float somefunc(char *somedata){

float output=countzero();       //someother function not listed

return output;
}

void* thread_function()
{
    pthread_mutex_lock (&mutexdata);

    int currentthread = this->whichthread;
    this->whichthread+=1;

        pthread_mutex_unlock (&mutexdata);

    entity *ent = this->entity_array[currentthread];


    double A=0,B=0,C=0,D=0,E=0,F=0;
    int i,j,k,l;



         A = somefunc(ent->somedata[0]);
         B = somefunc(ent->somedata[1]);

        t4 = anotherfunc(A,B);



        ent->output   = t4;
        ent->fitness  = sqrt(pow(t4,2)); 





                    }



static void* staticthreadproc(void* p){


return reinterpret_cast<ga*>(p)->thread_function();

}


void eval_thread(){

//use multithreading to evaluate individuals in parallel 

int i,j,k;
nthreads = this->numthreads;
pthread_t threads[nthreads];

//create threads
pthread_mutex_init(&this->mutexdata,NULL);
this->whichthread=0;

for(i=0;i<nthreads;i++){

pthread_create(&threads[i],NULL,&ga::staticthreadproc,this);

//printf("creating thread, %d\n",i);
}


//join threads
for(i=0;i<nthreads;i++){

pthread_join(threads[i],NULL);

}

}

};

ここで pthread を使用しているのは、メモリの少ないマシンではブーストよりもうまく機能するためです。各スレッドは eval_thread で開始され、そこで終了します。各スレッドは、変数 this->whichthread によってインデックス付けされたそれぞれの entity_array にのみ作業を適用するため、mutex を使用して、すべてのスレッドが entity_array の正しいインデックスで開始されるようにしています。この変数は、スレッドごとに更新され、他のスレッドによって変更されてはならないため、ミューテックスによってロックする必要がある唯一のものです。thread_function、eval_threads、および staticthreadproc を除く他のすべての関数は、init を除く他のすべての関数がプロセッサとメモリの両方を集中的に使用することを想定している唯一の関連関数であるため、喜んで無視できます。

では、私の質問は、この方法でマルチスレッドを使用すると、スレッドをまったく使用しない従来の方法よりもメモリと速度の面で IT のコストが高くなるのはなぜですか?

繰り返しますが、コードは疑似コードであり、問​​題はコンパイルできるかどうかではありません。

ありがとうございます。pthread やブースト ソリューションに関するご提案をいただければ幸いです。

4

2 に答える 2

2

各スレッドには、メモリを消費する独自の呼び出しスタックが必要です。関数 (およびコール スタック上の他のすべての関数) のすべてのローカル変数は、そのメモリにカウントされます。

新しいスレッドを作成すると、その呼び出しスタック用のスペースが予約されます。pthread のデフォルト値はわかりませんが、調べてみてください。デフォルトで予約されているよりも少ないスタックスペースが必要であることがわかっている場合は、スレッドを生成するときに目的のスタックサイズを明示的に指定することで、メモリ消費を大幅に削減できる可能性があります。

パフォーマンス部分に関しては、いくつかの問題に依存する可能性があります。一般に、コア数よりも多くのスレッドに数計算操作を並列化することでパフォーマンスの向上を期待するべきではありません (ここで当てはまるかどうかはわかりません)。これは、コンテキスト スイッチの追加のオーバーヘッド、キャッシュ ミスの増加などにより、遅くなる可能性があります。プラットフォームに応じて、これをプロファイリングする方法があります (たとえば、Visual Studio プロファイラーはキャッシュ ミスをカウントできます)。 、Linux用のツールもあります)。

于 2012-11-28T15:46:42.050 に答える
0

スレッドの作成は、非常にコストのかかる操作です。各スレッドが非常に少量の作業しか行わない場合、プログラムはそれらすべてを作成するのにかかる時間によって支配される可能性があります。また、アクティブなスレッドが多数あると、それらをスケジュールするために必要な作業が増加し、システムのパフォーマンスが低下する可能性があります。また、別の回答が言及しているように、各スレッドには独自のスタック メモリが必要であるため、スレッドの数に応じてメモリ使用量が増加します。

もう 1 つの問題は、キャッシュの無効化です。1 つのスレッドがその結果をそのentity構造体に書き込むと、近くにキャッシュされたメモリが無効になり、他のスレッドが上位レベルのキャッシュまたはメイン メモリからデータをフェッチするように強制される可能性があります。

より少ない数のスレッドを使用し、それぞれがより多くのデータのサブセットを処理する場合、より良い結果が得られる可能性があります。このような CPU バウンドのタスクでは、CPU ごとに 1 つのスレッドがおそらく最適です。つまり、すべての CPU をビジー状態に保つことができ、それぞれに複数のスレッドをスケジュールする時間を無駄にする必要はありません。各スレッドが動作するエンティティが配列内に一緒に配置されていることを確認してください。これにより、他のスレッドによってキャッシュされたエンティティが無効になりません。

于 2012-11-28T16:02:27.207 に答える