none
デュアルコアでスレッドの配列処理 RRS feed

  • 質問

  • Pentium Dプロセッサの搭載されているDELL GX620(2GBメモリ)で、配列処理のプログラムを作成しようとしています。

    大きな配列で簡単な処理を行った時、2つのスレッドで実行すると、1つのスレッドの場合より、処理時間が長くなることがあります。

    以下のプログラム例は、簡略化したものです。

     

    int  tab[4000*4000*4];

    void sub(int n){

        for (j=0; j<n * 4000 * 4; j++){

            tab[j] = j;

        }

    }

    int main(){

        sub(4000);    // 実際には、VirtualLock()で配列をロック

        QueryPerformanceCounter(&t1);

        sub(4000);

        QueryPerformanceCounter(&t2);

        CreateThread(0,0, sub, 2000, 0,0);

        CreateThread(0,0, sub, 2000, 0,0);

        WaitForMultipleObjects();

        QueryPerformanceCounter(&t3);

    }

     

    CreateThread(0,0, sub, 2000, 0,0)が、1回だけの時には、半分のデータ量なので、sub(4000)の処理時間の半分になります。

    上記のように、スレッドを2つ実行すると、sub(4000)の処理時間とほぼ同じ位になります。

    2つのスレッドで、小さな配列の処理を行ったり、演算のループを行う時には、2つのスレッドに分ければ、半分の処理時間になります。なぜ、上記のようなケースでは、スレッドが効果的ではないのでしょうか。

     

     

    2008年6月4日 5:15

回答

  • 「// 実際には、VirtualLock()で配列をロック」の部分がナゾなので何とも言えないのですが、

    2つのスレッドがリソース(この場合は配列)を共有していたら、倍以上の時間がかかってもおかしくありません。

    片方のスレッドが何かしている間、もう片方は配列に手出しできないのだとすると、結局1人でやっているのと同じことです。

    Lock, Unlock やスレッドの切り替え時間を考えると、1人でやったほうが速いなんてことになってしまいます。

     

    あとは CPU への割り当てでしょうか。

    2つのスレッドがそれぞれの CPU にきれいに割り当てられるかどうかは OS 次第だと思いますので、

    SetThreadAffinityMask 等で明示的に割り当てるとうまくいくかも知れません。

     

    完全なサンプルがあれば、手元の Core 2 で試してみますよ。

    2008年6月4日 10:52
  • CPUのキャッシュミスが原因ではないでしょうか。

    以下の例では私の環境(Core2Duo)でFuncAの方が1.2~1.5倍くらい高速です。

    2つのスレッドに分けた場合はFuncBと同様のメモリアクセスが発生するためスレッドの効果が相殺されてしまうのではないかと思います。

     

    Code Snippet

    int tab[2][4000*4000*2];

    void FuncA()
    {
     for(int x=0; x<2 ; x++){
      for(int y=0; y< 2000 * 4000 * 4; y++){
       tab[x][y] = x;
      }
     }
    }
    void FuncB()
    {
     for(int y=0; y< 2000 * 4000 * 4; y++){
      for(int x=0; x< 2; x++){
       tab[x][y] = x;
      }
     }
    }

     

     

    2008年6月4日 13:00

すべての返信

  • 「// 実際には、VirtualLock()で配列をロック」の部分がナゾなので何とも言えないのですが、

    2つのスレッドがリソース(この場合は配列)を共有していたら、倍以上の時間がかかってもおかしくありません。

    片方のスレッドが何かしている間、もう片方は配列に手出しできないのだとすると、結局1人でやっているのと同じことです。

    Lock, Unlock やスレッドの切り替え時間を考えると、1人でやったほうが速いなんてことになってしまいます。

     

    あとは CPU への割り当てでしょうか。

    2つのスレッドがそれぞれの CPU にきれいに割り当てられるかどうかは OS 次第だと思いますので、

    SetThreadAffinityMask 等で明示的に割り当てるとうまくいくかも知れません。

     

    完全なサンプルがあれば、手元の Core 2 で試してみますよ。

    2008年6月4日 10:52
  • CPUのキャッシュミスが原因ではないでしょうか。

    以下の例では私の環境(Core2Duo)でFuncAの方が1.2~1.5倍くらい高速です。

    2つのスレッドに分けた場合はFuncBと同様のメモリアクセスが発生するためスレッドの効果が相殺されてしまうのではないかと思います。

     

    Code Snippet

    int tab[2][4000*4000*2];

    void FuncA()
    {
     for(int x=0; x<2 ; x++){
      for(int y=0; y< 2000 * 4000 * 4; y++){
       tab[x][y] = x;
      }
     }
    }
    void FuncB()
    {
     for(int y=0; y< 2000 * 4000 * 4; y++){
      for(int x=0; x< 2; x++){
       tab[x][y] = x;
      }
     }
    }

     

     

    2008年6月4日 13:00
  • アドバイスをありがとうございました。
    1280x800のカメラ画像を取り込み、補間や明るさ調整などの処理を行って、1280x800のウィンドウに、30コマ秒で連続表示しようとしていましたが、なんとかメドが立ちました。


    VirtualLock()は、大きな実メモリを最初から確保しようとしたものです。Process::WorkingSetで見ると、プログラム起動時には、数メガバイトしか確保されておらず、最初のサブルーチンコールにとても時間がかかります。


    明るさの調整やアルファ値を連続的に変更するなど、マルチメディア関連の処理では、大きなメモリ域を更新する処理が多くあるのではないかと思います。皆さんは、メモリ処理なので遅くて当然と考えておられるようで、そんなものかと。

    2008年6月6日 11:06
  • こんにちは!中川 俊輔です。

     

    zakioさん、C.Johnさん、回答ありがとうございます。

     

    vcvcさん、フォーラムのご利用ありがとうございます。

    有用な情報と思われたため、zakioさん、C.Johnさんの回答へ回答済みチェックをつけさせていただきました。

     

    回答済みチェックが付くことにより、有用な情報を探している方が情報を見つけやすくなります。
    有用な情報と思われる回答があった場合は、なるべく回答済みボタンを押してチェックを付けてください。

     

    vcvcさんはチェックを解除することもできますので、ご確認ください。

    それでは!

    2008年6月24日 8:41