0

私の C++ コードは、時系列データ (t2 >> t1) で非常に大きな積分を評価します。積分は固定長で、現在 [mx 2] 倍精度の列配列に格納されています。列 1 は時間です。列 2 は、統合されている信号です。コードは、クアッドコアまたは 8 コアのマシンで実行されています。

k 個のコアを持つマシンの場合、次のことを行います。

  • k-1 個のワーカー プロセス (残りのコアごとに 1 つ) をスピンオフして、積分 (台形積分) の一部を評価し、その結果を待機中のマスター スレッドに返します。
  • 元の配列の一部をディープ コピーせずに上記を実現します。
  • 移植性のために C++11 非同期テンプレートを実装する

利用可能なコアの数をハードコーディングせずに上記を達成するにはどうすればよいですか?

私は現在VS 2012を使用しています。

明確にするための更新:

たとえば、大まかな疑似コードは次のとおりです。

data is [100000,2] double

result = MyIntegrator(data[1:50000,1:2]) + MyIntegrator(data[50001:100000, 1:2]); 

MyIntegrator()関数を別のスレッドで評価する必要があります。マスター スレッドは 2 つの結果を待ちます。

4

5 に答える 5

2

実行中のコアの数を取得します。通常、これは次のように確認できます。std::thread::hardware_concurrency()

実装でサポートされている同時スレッドの数を返します。値は単なるヒントと見なす必要があります。

これがゼロの場合は、OSに基づいて特定のコマンドを実行してみることができます。 これは、コアの数を知るための良い方法のようです。

マルチスレッドが具体的なメリットをもたらすかどうかを判断するには、テストを行う必要があります。時期尚早に最適化しないように注意してください:)

于 2013-01-28T19:42:07.033 に答える
2

これは、問題のマルチスレッド統合を行うソースです。

#include <vector>
#include <memory>
#include <future>
#include <iterator>
#include <iostream>

struct sample {
  double duration;
  double value;
};
typedef std::pair<sample*, sample*> data_range;
sample* begin( data_range const& r ) { return r.first; }
sample* end( data_range const& r ) { return r.second; }

typedef std::unique_ptr< std::future< double > > todo_item;

double integrate( data_range r ) {
  double total = 0.;
  for( auto&& s:r ) {
    total += s.duration * s.value;
  }
  return total;
}

todo_item threaded_integration( data_range r ) {
  return todo_item( new std::future<double>( std::async( integrate, r )) );
}
double integrate_over_threads( data_range r, std::size_t threads ) {
  if (threads > std::size_t(r.second-r.first))
    threads = r.second-r.first;
  if (threads == 0)
    threads = 1;
  sample* begin = r.first;
  sample* end = r.second;

  std::vector< std::unique_ptr< std::future< double > > > todo_list;

  sample* highwater = begin;

  while (highwater != end) {
    sample* new_highwater = (end-highwater)/threads+highwater;
    --threads;
    todo_item item = threaded_integration( data_range(highwater, new_highwater) );
    todo_list.push_back( std::move(item) );
    highwater = new_highwater;
  }
  double total = 0.;
  for (auto&& item: todo_list) {
    total += item->get();
  }
  return total;
}

sample data[5] = {
  {1., 1.},
  {1., 2.},
  {1., 3.},
  {1., 4.},
  {1., 5.},
};
int main() {
  using std::begin; using std::end;
  double result = integrate_over_threads( data_range( begin(data), end(data) ), 2 );
  std::cout << result << "\n";
}

指定した正確な形式でデータを読み取るには、いくつかの変更が必要です。

std::thread::hardware_concurrency()ただし、スレッドの数として呼び出すことができ、機能するはずです。

(特に、単純にするために、(時間、値) ではなく (期間、値) のペアがありますが、それはほんの些細なことです)。

于 2013-01-28T21:01:39.537 に答える
2

どうstd::thread::hardware_concurrency()ですか?

于 2013-01-28T19:35:07.877 に答える
1

スケジュールをオーバーして、パフォーマンスが低下するかどうかを確認できます。配列を小さな固定長の間隔 (1 つの量で計算可能、1 つのキャッシュ ページに収まる可能性があります) に分割し、CPU の数に応じて分割した場合のパフォーマンスを比較します。

std::packaged_task を使用してスレッドに渡し、「起動」構成によって問題が発生しないようにします。

次のステップはスレッド プールの導入ですが、それはより複雑です。

于 2013-01-28T20:40:31.193 に答える
0

ワーカースレッドの数のコマンドラインパラメーターを受け入れることができます。

于 2013-01-28T19:34:12.370 に答える