0

我的 C++ 代码在时间序列数据 (t2 >> t1) 上计算非常大的积分。积分是固定长度的,当前存储在双精度的 [mx 2] 列数组中。第 1 列是时间。第 2 列是被整合的信号。代码在四核或八核机器上运行。

对于具有k核的机器,我想:

  • 分拆 k-1 个工作进程(每个剩余核心一个)以评估积分的部分(梯形积分)并将其结果返回到等待的主线程。
  • 在不深度复制原始数组部分的情况下实现上述目标。
  • 实现 C++11 异步模板以实现可移植性

如何在不硬编码可用内核数量的情况下实现上述目标?

我目前正在使用 VS 2012。

更新清晰度:

例如,这是粗略的伪代码

data is [100000,2] double

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

我需要MyIntegrator()在单独的线程中评估函数。主线程等待这两个结果。

4

5 回答 5

2

怎么样std::thread::hardware_concurrency()

于 2013-01-28T19:35:07.877 回答
2

获取运行的核心数量,通常可以通过std::thread::hardware_concurrency()

返回实现支持的并发线程数。该值应仅被视为一个提示。

如果这是零,那么您可以尝试运行基于操作系统的特定命令。 似乎是找出核心数量的好方法。

您仍然需要进行测试以确定多线程是否会给您带来实实在在的好处,请记住不要过早优化:)

于 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()线程数来调用它,它应该可以工作。

(特别是,为了简单起见,我有成对的 (duration, value) 而不是 (time, value),但这只是一个小细节)。

于 2013-01-28T21:01:39.537 回答
1

你可以过度安排,看看它是否会损害你的表现。将您的数组拆分为固定长度的小间隔(可在一个 quant 中计算,可能适合一个缓存页面),并查看其性能与根据 CPU 数量进行拆分的比较。

使用 std::packaged_task 并将其传递给线程以确保您不会受到“启动”配置的伤害。

下一步将是引入线程池,但这更复杂。

于 2013-01-28T20:40:31.193 回答
0

您可以接受工作线程数的命令行参数。

于 2013-01-28T19:34:12.370 回答