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

Is it much faster to re-initialize a vector using OpenMP threads?

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

一般答案需要 "it depends, you have to measure",因为 C++ 中的初始化可能很简单,也可能非常昂贵,具体取决于类型。您没有提供太多细节,因此必须猜测一下。
如果 class 有一个计算量大的构造函数,并行化工作 可能 非常值得。

您的具体措辞 "initialize to value" 表明您的向量包含 POD(例如,整数?)。我假设是这种情况。

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

然而,并行化可能会很慢,原因有几个(我不打算详细说明,足以说明它不太可能更快)。

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

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

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

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