C++ std::log 函数无法缩放

标签 c++ multithreading c++11

我正在运行一段代码来测试 log() 函数是否可以缩放。我在4核机器上运行它,结果显示它没有扩展。我的代码如下:

#include<iostream>
#include<cmath>
#include<omp.h>
#include<chrono>
using namespace std;

typedef std::chrono::milliseconds ms;

int main(){
        #pragma omp parallel for schedule(static)
        for(int i=0;i<4;i++){
                auto start = std::chrono::high_resolution_clock::now();

                double tmp=1.0;
                for(double j=0.0;j<10000000;j++){
                        tmp=log(j);
                }

                auto end = std::chrono::high_resolution_clock::now();
                #pragma omp critical
                {
                        cout<<"tmp="<<tmp<<endl;
                        cout<<"Thread "<<omp_get_thread_num()<<" calculated tmp, time used: "<<std::chrono::duration_cast<ms>(end - start).count() << "ms" << endl;
                }
        }

        return 0;
}

如果我使用4个线程,结果是:

Thread 1 calculated tmp, time used: 21ms
Thread 0 calculated tmp, time used: 21ms
Thread 2 calculated tmp, time used: 21ms
Thread 3 calculated tmp, time used: 21ms

如果只使用1个线程,结果是:

Thread 0 calculated tmp, time used: 20ms
Thread 0 calculated tmp, time used: 16ms
Thread 0 calculated tmp, time used: 16ms
Thread 0 calculated tmp, time used: 15ms

因此,并行运行时,每个线程比顺序运行花费的时间更长。有谁知道为什么它不能扩展? std::log 实际上是如何工作的(线程可能必须共享某些内容)?有没有办法让 log() 函数可以扩展?谢谢!

编辑1: 我将迭代次数增加到 10e10 次,但结果表明并行版本甚至更慢,所以也许这里的主导因素不是线程创建时间。 4 个线程:

Thread 0 calculated tmp, time used: 17890ms
Thread 2 calculated tmp, time used: 17890ms
Thread 1 calculated tmp, time used: 17892ms
Thread 3 calculated tmp, time used: 17892ms

1 个线程:

Thread 0 calculated tmp, time used: 15664ms
Thread 0 calculated tmp, time used: 15659ms
Thread 0 calculated tmp, time used: 15660ms
Thread 0 calculated tmp, time used: 15647ms

EDIT2:我让 tmp 变量最后打印出来,这样 log() 就无法优化出来。但结果还是和以前一样。还有其他想法吗?

EDIT3:所以总执行时间的加速比是3.5,即使迭代次数增加,它也不会变得更高。我不确定这是否是一个合理的加速比,因为我预计像这样的简单程序会有 3.7 或 3.8 的加速比。

最佳答案

简而言之

你说得完全正确。但要充分衡量多核性能的改进,您不应仅仅依赖于对各个线程进行计时:您还应该衡量整体执行的时间。

多核架构似乎可以实现更高的吞吐量,但代价是当其中几个核心处于事件状态时,每个核心的数量会略有下降。这里another benchmark (使用 std::thread 而不是 OMP)具有类似的观察结果。

因此,每个单独的日志计算都无法扩展,但整体系统表现得很好。

其他详细信息

如果您要运行一些总体端到端测量:

int main()
{
    auto common_start = std::chrono::high_resolution_clock::now();
    ... 
    auto common_end = std::chrono::high_resolution_clock::now();
    cout << "Overall calculated time : " << std::chrono::duration_cast<ms>(common_end - common_start).count() << "ms" << endl;
    return 0; 
}

您肯定会同时观察到更好的整体性能。

这是我自己的 4 个线程的计时:

Thread 2 calculated tmp, time used: 269ms
Thread 3 calculated tmp, time used: 274ms
Thread 0 calculated tmp, time used: 281ms
Thread 1 calculated tmp, time used: 289ms
Overall calculated time : 296ms

还有一个:

Thread 0 calculated tmp, time used: 218ms
Thread 0 calculated tmp, time used: 218ms
Thread 0 calculated tmp, time used: 229ms
Thread 0 calculated tmp, time used: 224ms
Overall calculated time : 903ms

正如您所观察到的,使用一个线程,计算速度提高了 22%。但总的来说,完成相同数量的计算需要多线程所需时间的 3 倍。

所以这一切都与吞吐量有关:单线程运行速度仅为 44 K 迭代/毫秒,而多线程运行速度为 135 K 迭代/毫秒。

关于C++ std::log 函数无法缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38279689/

相关文章:

c++ - C++中具有构造函数的模板化typedef结构

c++ - 类间比较

c++ - const 对象的无锁重载和共享

c++ - Windows Mobile 6.x 上的默认查看器

java - 使用 Future 异步读取文件

c++ - 不断检查C++中的变量

android - 如何确定性地使用 std::this_thread::yield() ?

c++ - 为什么相继声明的两个变量在内存中并不相邻?

c++ - 错误 C2512 但我有可用的默认构造函数

Android - 在计时器内重复运行线程