0

私は conditional_variables の使用に慣れていないので、ここで簡単に愚かなことをすることができますが、関数を直接呼び出すのではなく、ブースト スレッドを使用すると、奇妙なパフォーマンスが得られます。func でブースト スレッドを作成する行を、単に func を直接呼び出すように変更すると、コードは数桁速く実行されます。ソースフォージからブーストスレッドプールソフトウェアを使用してみましたが、違いはありません...

コードは次のとおりです。

#include <boost/thread.hpp>


using namespace boost;

condition_variable cond;
mutex conditionalMutex;
int numThreadsCompleted = 0;
int numActiveThreads = 0;

void func()
{
  {
    lock_guard<mutex> lock(conditionalMutex);
    --numActiveThreads;
    numThreadsCompleted++;
  }
  cond.notify_one();
};


int main()
{
  int i=0;
  while (i < 100000)
    {
      if (numActiveThreads == 0)
        {
          ++numActiveThreads;
          thread thd(func);
          //Replace above with a direct call to func for several orders of magnitude
          //performance increase...
          ++i;
        }
      else
        {
          unique_lock<mutex> lock(conditionalMutex);
          while (numThreadsCompleted == 0)
            {
              cond.wait(lock);
            }
          numThreadsCompleted--;
        }
    }
  return 0;
}
4

3 に答える 3

1

関数を直接呼び出すよりも、パフォーマンスが大幅に低下する必要があります。1つのスレッドを開始し、そのスレッドが終了するのを待ちます。開始スレッドのオーバーヘッドをゼロに減らしても、そのスレッドと通信します。また、少なくとも1つのコンテキストスイッチがあり、func()は基本的に何も実行していないため、そのオーバーヘッドが大きな要因になります。func()にペイロードを追加すると、比率が変わります。やらなければならないことが非常に少ない場合は、このことを見つけたスレッドでそれを実行してください。

ところで:ミューテックスをロックせずにnumActiveThreadsに書き込むため、競合状態が発生します。上記のコードは次のように要約されます。

int main()
{
    int i=0;
    while (i < 100000)
    {
        thread thd(func);
        thd.join();
        ++i;
    }

    return 0;
}

そして、これが以下よりも速くなければならない理由は本当にありません。

int main()
{
    int i=0;
    while (i < 100000)
    {
        func();
        ++i;
    }

    return 0;
}
于 2012-08-17T10:38:01.140 に答える
0

スレッドの作成と破棄によるオーバーヘッドに加えて、分岐予測がパフォーマンスの違いに寄与している可能性があります。

スレッドを使用しない場合、各ループ反復の開始時と終了時と同様numActiveThreadsに、if ステートメントは常に true です。0

while (i < 100000)
{
  if (numActiveThreads == 0) // branch always taken
  {
    ++numActiveThreads; // numActiveThreads = 1
    func();             // when this returns, numActiveThreads = 0
    ++i;                
  }
}

これにより、次の結果が得られます。

  • 分岐予測は決して失敗しません。
  • スレッドの作成/破棄のオーバーヘッドはありません。
  • を取得するためにブロックされた待機時間はありませんconditionalMutex

スレッド化では、順次反復さnumActiveThreadsれる場合とされない場合があります。0私がテストしたほとんどのマシンでは、短い予測可能なパターンが観察され、反復ごとに if ステートメントと else ステートメントが交互に分岐していました。ただし、if ステートメントが順次反復で選択されることがあります。したがって、次のことで時間が浪費される可能性があります。

  • 分岐予測失敗。
  • スレッドの作成と破棄。作成と破棄が同時に行われる場合、基になるスレッド ライブラリで同期が発生している可能性があります。
  • の取得conditionMutexまたは待機中のブロックがブロックされましたcond
于 2012-08-16T04:12:57.070 に答える
0

スレッドを作成および破棄しています。スレッドは通常、低レベルの OS 構造として実装され、通常はある種の軽量プロセスです。この作成と破棄にはコストがかかる場合があります。

最後に、あなたは基本的にやっています

  1. スレッドを作成
  2. スレッドが終了するのを待ちます

何度も何度も。これは作成/破棄を意味し、毎回それを行っているため、コストが加算されます。

于 2012-08-16T01:36:59.600 に答える