1

我有一种情况,我需要做一些繁重的计算。我发现细分我的数据然后将其合并在一起是最快的(随着大小的增加,时间增加得更快,所以拆分是合乎逻辑的)。

它应该能够为应用程序提供数据大小,例如一百万个双精度值。

我现在所拥有的是将基于此大小的创建数据发送到某个函数,在计算后将其返回,然后循环返回以将此数据卸载到主向量中。

我想发送 200 个部分,其中一个“最后”部分。例如,给定 size = 1000005 最初将执行此函数 5000 次,然后是最后一个大小为 5 的数据。

int size = 1000000;
int times = size / 200; // 5000
int leftover = size % 200; // 0, this not performed

QVector<double> x(size);
QVector<double> y(size);

x = createData(size);
x = createData(size);

for (int i = 0; i < times; i++)
{
    holder = createData(200);
    QVector<double> tempx = x.mid(i*200, 200);
    QVector<double> tempy = y.mid(i*200, 200);
    holder = myfunction(tempx, tempy, 200);  // let it now just return `tempy`
    for (int j = 0; j < 200; j++)
    {
        y[i*200 + j] = holder[j];
    }
}
// leftover function here, really similar to this part before.

// plotting function here

最后,x将保持初始化状态,y进行计算。

由于这些代码部分可以彼此分开运行并且速度至关重要,因此我想使用几个内核。

以下进一步描述了这种情况:

  • 这些函数调用是相互独立的,只有当向量完成时,我才想绘制结果。
  • 每次通话的完成时间会有很大差异。
  • 的数量times应该是可变的。

我读过一些关于建议最大线程数是核心数(至少作为起点)的内容,因为使用太多线程可能会减慢进程。考虑到这种情况,排队系统/线程池似乎是有意义的,因为当一个线程有一些简单的工作而其他线程通过更难的工作减慢一切时,不会浪费时间。

虽然在几十个教程中使用一些(通常是 2 个)线程来打印一些消息似乎很容易,但任何人都可以提供更详细的帮助,说明如何返回向量并将这些线程安全地卸载到主函数中,以及如何创建线程池等时间不会浪费吗?

使用 Ubuntu 13.04、Qt 和 C++11x,虽然没关系。

4

3 回答 3

4

首先,写一个tread pool是很难的。如果你真的想学习如何编写一个,Antony Williams 所写的 C++ Concurrency in Action 一书会教你如何实现。

但是,您的情况似乎是一个简单的 parallel_for 非常适合的情况。所以我建议使用 Intel Threading Building Blocks library。该库的优点是它有一个非常好的线程池,并且与 C++11 特性配合得非常好。

示例代码:

#include "tbb/task_scheduler_init.h"
#include "tbb/blocked_range.h"
#include "tbb/parallel_for.h"
#include "tbb/tbb_thread.h"
#include <vector>

int main() {
  tbb::task_scheduler_init init(tbb::tbb_thread::hardware_concurrency());
  std::vector<double> a(1000);
  std::vector<double> c(1000);
  std::vector<double> b(1000);

  std::fill(b.begin(), b.end(), 1);
  std::fill(c.begin(), c.end(), 1);

  auto f = [&](const tbb::blocked_range<size_t>& r) {
    for(size_t j=r.begin(); j!=r.end(); ++j) a[j] = b[j] + c[j];    
  };
  size_t hint_number_iterations_per_thread = 100;
  tbb::parallel_for(tbb::blocked_range<size_t>(0, 1000, hint_number_iterations_per_thread), f);
  return 0;
}

完毕!英特尔 TBB 有一个非常好的线程池,它会尝试调整每个线程的工作负载。只要hint_number_iterations_per_thread不是一个疯狂的数字,就会非常接近最优解

顺便说一句:intel TBB 是一个开源库,可与大多数编译器一起使用!

于 2013-08-31T22:57:14.230 回答
1

你不需要创造任何东西。如果你正在使用Qt,你的问题已经解决了。您可以从中派生一个类QRunnable,然后将其传递QThreadPool给执行。

您可以指示QThreadPool应该同时运行多少线程(任何额外的线程只是在队列中等待直到插槽打开)但这不是必需的,因为QThreadPool根据您的架构设置通常足够好的限制。

线程池

QRunnable

于 2013-09-01T10:56:49.140 回答
0

Even simpler than creating a QThreadPool and extending QRunabble, you can use the QtConcurrent library. Specifically use the QtConcurrent::mapped function, which takes a begin iterator and an end iterator, and a function (which can be a lambda), and internally handles the creation of, and execution on, a thread pool for you.

There are two variations: "mapped" returns a QFuture to the results but does not block the current thread, while "blockingMapped" directly returns a list of the results.

To square a large vector of integers, you could do the following:

std::vector<int> myInts = ....

QVector<int> result = QtConcurrent::blockingMapped(myInts.begin(), myInts.end(), [](int x) { return x*x}; });
于 2014-04-25T18:11:10.910 回答