改进多线程的一般技巧(在 C++ 中)

General tips to improve multithreading (in C++)

我已经构建了一个 C++ 代码,但没想到我以后会需要多线程。我现在已经使用 openMP 对 3 个主要的 for 循环进行了多线程处理。以下是性能比较(根据 bash 中的 time 测量)

单线程

real    5m50.008s
user    5m49.072s
sys     0m0.877s

多线程(24个线程)

real    1m22.572s
user    28m28.206s
sys     0m4.170s

24核的使用使实时时间减少了4.24倍。当然,我没想到代码会快 24 倍。我真的不知道会发生什么。

- 是否有一条经验法则可以让人们预测给定代码 运行 与 n 线程相比单线程会快多少?

- 是否有提高多线程进程性能的通用技巧?

我相信您知道明显的问题,例如障碍的成本。但是很难在微不足道的事情和对某人有帮助的事情之间划清界限。下面是一些使用中的经验教训,想到再补充:

  • 总是尽量使用线程私有变量,考虑到即使是减少,也只提供少量的集体结果。

  • 更喜欢并行运行长代码段和长并行段 (#pragma omp parallel ... #pragma omp for),而不是单独并行化循环 (#pragma omp parallel for)。

  • 不要并行化短循环。在二维迭代中,并行化外循环通常就足够了。如果您确实使用 collapse 将整个事情并行化,请注意 OpenMP 会将其线性化,引入融合变量并单独访问索引会产生开销。

  • 使用线程专用堆。尽可能避免共享池和集合,即使集合的不同成员将由不同的线程独立访问。

  • 剖析您的代码,看看在忙等待上花费了多少时间以及可能发生的位置。

  • 了解使用不同计划策略的后果。尝试更好的,不要假设。

  • 如果您使用关键部分,请给它们命名。所有未命名的CSs都得互相等待

  • 如果您的代码使用随机数,请使其可重现:定义线程本地 RNG,以可控方式播种所有内容,对缩减施加顺序。确定性基准,而非统计基准。

  • 在 Stack Overflow 上浏览类似问题,例如精彩的答案