8

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

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

我的机器有 Intel Core i7 处理器 2.2 GHz 和 8 GB RAM,运行 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 有任何显着差异。

感谢大家的帮助。

4

2 回答 2

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等待任务完成。

于 2012-11-30T15:17:46.913 回答
3

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

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

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

于 2012-12-01T01:53:36.957 回答