C ++ 0x线程没有加速

时间:2012-11-30 15:16:13

标签: c++ multithreading c++11 parallel-processing future

我编写了一个程序,用于使用c ++ 0x线程搜索数组中的最大值(用于学习目的)。为了实现,我使用了标准的线程 future 类。但是,并行化功能不断显示与非并行化相同或更差的运行时间。

代码如下。我试图将数据存储在一维数组,多维数组中,最后得到几个数组。但是,没有选择取得好成绩。我试图从Eclipse和命令行编译和运行我的代码,仍然没有成功。我也尝试过类似的测试而不使用数组。并行化只提高了20%的速度。从我的角度来看,我运行非常简单的并行程序,没有锁和几乎没有资源共享(每个线程在他自己的数组上运行)。什么是瓶颈?

我的机器配备2.2 GHz英特尔酷睿i7处理器和8 GB内存,运行Ubuntu 12.04。

const int n = 100000000;

int a[n], b[n], c[n], d[n];

int find_max_usual() {
    int res = 0;
    for (int i = 0; i < n; ++i) {
        res = max(res, a[i]);
        res = max(res, b[i]);
        res = max(res, c[i]);
        res = max(res, d[i]);
    }
    return res;
}

int find_max(int *a) {
    int res = 0;
    for (int i = 0; i < n; ++i)
        res = max(res, a[i]);
    return res;
}

int find_max_parallel() {
    future<int> res_a = async(launch::async, find_max, a);
    future<int> res_b = async(launch::async, find_max, b);
    future<int> res_c = async(launch::async, find_max, c);
    future<int> res_d = async(launch::async, find_max, d);
    int res = max(max(res_a.get(), res_b.get()), max(res_c.get(), res_d.get()));
    return res;
}

double get_time() {
    timeval tim;
    gettimeofday(&tim, NULL);
    double t = tim.tv_sec + (tim.tv_usec / 1000000.0);
    return t;
}

int main() {
    for (int i = 0; i < n; ++i) {
        a[i] = rand();
        b[i] = rand();
        c[i] = rand();
        d[i] = rand();
    }
    double start = get_time();
    int x = find_max_usual();
    cerr << x << " " << get_time() - start << endl;
    start = get_time();
    x = find_max_parallel();
    cerr << x << " " << get_time() - start << endl;
    return 0;
}

时间显示,find_max_parralel几乎所有时间都被

消耗
int res = max(max(res_a.get(), res_b.get()), max(res_c.get(), res_d.get()));

编译命令行

g++ -O3 -std=c++0x -pthread x.cpp

更新。问题解决了。我用同样的测试得到了理想的结果。 4个线程提供大约3.3个加速,3个线程提供大约2.5个加速,2个线程几乎理想地具有1.9个加速。我刚刚用一些新的更新重新启动了系统。我没有看到cpu负载和运行porgrams的任何显着差异。

感谢所有人的帮助。

2 个答案:

答案 0 :(得分:14)

您必须明确设置std::launch::async

future<int> res_c = async(std::launch::async, find_max, c);

如果省略了std::launch::async | std::launch::deferred标志,那么可以选择是否以异步方式或延迟方式启动任务。

当前版本的gcc使用std::launch::deferred,MSVC有一个运行时调度程序,它决定运行时应该如何运行任务。

另请注意,如果您想尝试:

std::async(find_max, c);

这也会阻止,因为std::future的析构函数等待任务完成。

答案 1 :(得分:3)

我刚用gcc-4.7.1运行相同的测试,并且线程版本大约快4倍(在4核服务器上)。 所以问题显然不在std :: future实现中,而是选择不适合您环境的线程设置。如上所述,您测试的不是CPU,而是内存密集型,因此瓶颈肯定是内存访问。 你可能想要运行一些cpu密集型测试(比如高精度地计算PI编号)来正确地测试线程。

如果不尝试不同数量的线程和不同的数组大小,很难说,究竟瓶颈在哪里,但可能很少有事情在发挥作用:   - 你可能有2通道内存控制器(它是2或3),所以超过2个线程只会引入额外的内存访问争用。因此,关于没有锁定和没有资源共享的论点是不正确的:在硬件层面上存在围绕并发内存访问的争论。   - 通过将数据预取到缓存中,可以有效地优化非并行版本。另一方面,有可能在并行版本中,您最终会进行密集的上下文切换,从而导致CPU缓存崩溃。

对于这两个因素,如果将线程数调低为2,则可能会看到加速。