2

通常 50 回実行される関数があります (50 回のシミュレーションを実行するため)。通常、これはシングルスレッドで順次実行されますが、複数のスレッドを使用して速度を上げたいと考えています。スレッドはお互いのメモリやデータにアクセスする必要がないので、レースが問題になることはないと思います。基本的に、スレッドはそのタスクを完了し、終了したメインに戻り、double 値も返す必要があります。

まず第一に、boost のすべてのドキュメントと例に目を通してみると、本当に複雑で、もう何を探しているのかわかりません。ブースト::スレッド? 未来を後押しする?誰かが私の場合に当てはまるものの例を挙げてもらえますか? さらに、実行するスレッド数を指定する方法がわかりません。50 スレッドを実行し、OS がそれらを実行するタイミングを処理するようなものですか?

4

2 に答える 2

4

コードが完全にCPUにバインドされている(ネットワーク/ディスクIOがない)場合は、CPUと同じ数のバックグラウンドスレッドを開始することでメリットが得られます。Boostのhardware_concurrency()関数を使用して、その数を決定したり、ユーザーが設定できるようにします。スレッドの束を開始するだけでは、スレッドの作成、切り替え、および終了によって発生するオーバーヘッドが増加するため、役に立ちません。

スレッドを開始するコードは単純なループであり、その後にスレッドの完了を待機する別のループが続きます。そのためにthread_groupクラスを使用することもできます。ジョブの数が不明で、スレッドの起動時に分散できない場合は、適切な数のスレッドを開始し、起動中にジョブを与えるスレッドプールの使用を検討してください。

于 2013-01-20T09:18:43.710 に答える
1

フューチャを使用してこれを実現する方法については、Boost.Thread フューチャのドキュメントを参照してください。asyncまた、オブジェクトを使用して手動で (難しい方法で) 行う方法も示しthreadます。

このシリアルコードを考えると:

double run_sim(Data*);

int main()
{
  const unsigned ntasks = 50;

  double results[ntasks];
  Data data[ntasks];

  for (unsigned i=0; i<ntasks; ++i)
    results[i] = run_sim(data[i]);
}

単純な並列バージョンは次のようになります。

#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/thread/future.hpp>
#include <boost/bind.hpp>

double run_task(Data*);

int main()
{
  const unsigned nsim = 50;

  Data data[nsim];
  boost::future<int> futures[nsim];

  for (unsigned i=0; i<nsim; ++i)
    futures[i] = boost::async(boost::bind(&run_sim, &data[i]));

  double results[nsim];
  for (unsigned i=0; i<nsim; ++i)
    results[i] = futures[i].get();
}

boost::asyncは遅延関数をまだサポートしていないため、非同期呼び出しごとに新しいスレッドが作成されるため、一度に 50 のスレッドが生成されます。これはパフォーマンスが非常に悪い可能性があるため、小さなブロックに分割できます。

#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/thread/future.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>

double run_sim(Data*);

int main()
{
  const unsigned nsim = 50;
  unsigned nprocs = boost::thread::hardware_concurrency();
  if (nprocs == 0)
    nprocs = 2;   // cannot determine number of cores, let's say 2

  Data data[nsim];   
  boost::future<int> futures[nsim];
  double results[nsim];

  for (unsigned i=0; i<nsim; ++i)
  {
    if ( ((i+1) % nprocs) != 0 )
      futures[i] = boost::async(boost::bind(&run_sim, &data[i]));
    else
      results[i] = run_sim(&data[i]);
  }

  for (unsigned i=0; i<nsim; ++i)
    if ( ((i+1) % nprocs) != 0 )
      results[i] = futures[i].get();
}

hardware_concurrency()4 が返された場合、これにより 3 つの新しいスレッドが作成され、スレッドrun_sim内で同期的に呼び出され、さらに 3 つの新しいスレッドが作成されてから同期的に呼び出されます。これにより、メイン スレッドが作業の一部を停止するため、一度に 50 個のスレッドがすべて作成されるのを防ぎ、他のスレッドの一部を完了することができます。main()run_sim

上記のコードには最新バージョンの Boost が必要です。C++11 を使用できる場合は、標準 C++ を使用する方が少し簡単です。

#include <future>

double run_sim(Data*);

int main()
{
  const unsigned nsim = 50;
  Data data[nsim];

  std::future<int> futures[nsim];
  double results[nsim];

  unsigned nprocs = std::thread::hardware_concurrency();
  if (nprocs == 0)
    nprocs = 2;

  for (unsigned i=0; i<nsim; ++i)
  {
    if ( ((i+1) % nprocs) != 0 )
      futures[i] = std::async(boost::launch::async, &run_sim, &data[i]);
    else
      results[i] = run_sim(&data[i]);
  }

  for (unsigned i=0; i<nsim; ++i)
    if ( ((i+1) % nprocs) != 0 )
      results[i] = futures[i].get();
}
于 2013-01-20T12:43:17.390 に答える