使用 OpenMP 线程重新初始化向量是不是更快?

Posted

技术标签:

【中文标题】使用 OpenMP 线程重新初始化向量是不是更快?【英文标题】:Is it much faster to re-initialize a vector using OpenMP threads?使用 OpenMP 线程重新初始化向量是否更快? 【发布时间】:2016-08-17 17:24:20 【问题描述】:

我正在使用 OpenMP 库进行并行计算。我使用 C++ 向量,其大小通常为 1*10^5。在经历迭代过程时,我需要将这些大向量(不是线程私有,而是全局范围)重新初始化为初始值。哪种方法更快?使用#pragma omp for 还是#pragma omp single?

【问题讨论】:

【参考方案1】:

假设原始数据类型的简单初始化,初始化本身将受到内存或缓存带宽的限制。但是,在现代系统上,您必须使用多个线程来充分利用您的内存和缓存带宽。例如查看these benchmark results,其中前两行比较并行与单线程缓存,最后两行比较并行与单线程主内存带宽。在面向高性能的系统上,尤其是具有多个套接字的系统上,更多的线程对于利用可用带宽非常重要。

但是,重新初始化的性能并不是您应该关心的唯一事情。假设例如双精度浮点数,10e5 个元素等于 800 kb 内存,适合缓存。为了提高整体性能,您应该尝试确保在初始化后数据位于靠近内核的缓存中,以便稍后访问数据。在 NUMA 系统中(多个套接字对其本地内存的访问速度更快),这一点更为重要。

如果您确实同时初始化共享内存,请确保不要从不同的内核写入相同的缓存行,并尽量保持访问模式的规律,以免混淆 CPU 的预取器和其他聪明的魔法 .

一般建议是:从一个简单的实现开始,然后分析您的应用程序以了解瓶颈的实际位置。不要投资于复杂的、难以维护的、系统特定的优化,这些优化可能只会影响代码整体运行时的一小部分。如果事实证明这是您的应用程序的瓶颈,并且您的硬件资源没有得到很好的利用,那么您需要了解底层硬件(本地/共享缓存、NUMA、预取器)的性能特征并相应地调整您的代码。

【讨论】:

【参考方案2】:

一般的答案需要是“这取决于,你必须衡量”,因为 C++ 中的初始化可能是微不足道的或非常昂贵的,具体取决于类型。您没有提供太多细节,因此您必须猜测一下。 如果一个类有一个计算成本很高的构造函数,那么并行化工作可能非常值得。

您的具体措辞“初始化为值”表明您的向量包含 POD(例如,整数?)。我会假设是这种情况。

假设这一点,并行化几乎肯定不会更快。此操作受内存带宽的限制,一个 CPU 线程应该能够将内存带宽饱和到大约 99%。

但是,由于多种原因,并行化可能会非常慢(我不会详细说明,已经足够说它不太可能更快)。

【讨论】:

一个 CPU 线程应该能够将内存带宽饱和到大约 99%。 这是错误的。参见例如these benchmarks。

以上是关于使用 OpenMP 线程重新初始化向量是不是更快?的主要内容,如果未能解决你的问题,请参考以下文章

在openmp中使用不同线程组装矢量时缩放不良

OpenMP 中的同步

c++ openmp中的线程

OpenMP 矩阵向量乘法仅在一个线程上执行

OpenMP 子句共享与关键

C ++比较向量,更快的方式