多线程程序比单线程慢

西奥多·约翰逊

我创建了一个非常简单的测试程序,该程序可以计算某些标量c和矩阵A的c * A。您可以在此处在线运行它,也可以将以下代码粘贴到您喜欢的文本编辑器中:

#include <iostream>
#include <time.h>
#include <chrono>
#include <thread>

void fill_rand_matrix(double* mat, int n){
    
    for (int i=0;i<n;i++){
        mat[i]=static_cast <double> (rand()) / static_cast <double> (RAND_MAX)*20-10;
    }
}

void test(size_t m, size_t n, double alpha, double* X) {

        for (int j = 0; j < m; ++j) {
            for (int i = 0; i < n; ++i) {
                X[i+ j*n] *= alpha;
            }
        }       
}   

int main()
{
    int m=10000;
    int n=10000;
    double res_scaling=0.5;
    
    double* res=new double[m*n];
    fill_rand_matrix(res,n*m);
    
    auto begin1 = std::chrono::steady_clock::now();
    std::thread t1(test,0.5*m,n,res_scaling,res);
    std::thread t2(test,0.5*m,n,res_scaling,(double*)(res+(m/2)*n));
    t1.join();
    t2.join();
    auto end1= std::chrono::steady_clock::now();
    std::cout << "Time taken multithreaded = " << std::chrono::duration_cast<std::chrono::milliseconds>(end1 - begin1).count() << "[ms]" << std::endl;

    auto begin2 = std::chrono::steady_clock::now();
    test(m,n,res_scaling,res);
    auto end2= std::chrono::steady_clock::now();
    std::cout << "Time taken singlethreaded = " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - begin2).count() << "[ms]" << std::endl;

    return 0;
}

当我多次运行此代码时,多线程版本仅比单线程变体快一点,甚至更慢。如果我添加两个以上的线程,甚至会发生这种情况。即使该问题几乎可以随内核数量完美地扩展,多线程似乎也没有任何好处。此外,我设置的矩阵大小越高,运行时间的波动就越剧烈,有时多达20倍。

你知道这里发生了什么吗?

艾略特

我没有足够的知识来给出明确的答案,但是由于到目前为止还没有答案,我会尽力而为:


简短答案:

在大小为L的数组(其中L大于最大缓存的大小)上的多个顺序迭代将无法利用任何缓存来对数组进行新的缓存行访问(因为缓存使用了变体的LRU)。通过快速计算在大小为L的数组上快速迭代意味着访问(主)内存是瓶颈,并且将占用所有正在运行的进程/线程共享内存总线添加更多受主内存访问限制的线程只会导致它们之间的竞争。

(如果非常聪明,您的缓存可能会在将每个新数组数据传递到L2缓存之前就丢弃它们,这是因为您意识到在将其推出之前,您将无法使用它。这不会影响此过程,但会为其他人留下更多的缓存空间。)


更多信息:

对我来说, g++ -std=c++17 -O3 -pthread -S -fverbose-asm

...为汇编输出提供movups与该行两次关联的指令:

X[i+ j*n] *= alpha; // line 17

movupsx86并行化(SIMD)指令这样的SIMD指令通常将4 doubles放入一个巨大的寄存器中,以非常快速地进行计算(总共约10个时钟周期,但如果我错,请纠正我)。将此乘以4,即可在高速缓存行上完成工作:约40个周期。如果您不使用x86,则可能是使用具有类似并行化指令的CPU。

主内存访问速度很慢(从主内存中获取高速缓存行大约需要100-200个时钟周期[高速缓存行= 64字节的块〜= 16倍)]。

你的CPU将尝试预取数据,以帮助你,但是,因为你总是以更快的速度比数据总线可以提供请求从主内存中的数据,然后预取可能不仅有助于减少您的等待时间从说〜100至〜60,如果您幸运的话。无论哪种方式,等待主内存访问仍然是瓶颈。

请注意,这也可以从另一个方向进行,您可以使用更新的数组值填充缓存,但是在8MB左右之后,您将需要不断地将该数据发送回主内存。因此,实际上我们的上述估计是乐观的。


Nitpick:

test函数有一个小错误:

j < m并且i < n是单/无符号比较。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

多线程random_r比单线程版本慢

单线程通过单线

多线程比单线程快吗?

为什么我的多线程比单线程慢?

Akka-Stream实现比单线程实现慢

C ++:线程池比单线程慢?

C ++:简单的多线程示例不比单线程快

为什么C#中的多线程快速排序比单线程慢

从单线程到多线程图像处理

Vulkan中的多线程渲染(生成命令缓冲区)比单线程慢

为什么与CompletableFuture相比,多线程比单线程代码慢?

尽管多线程程序读取单独的txt文件,为什么它们比单线程程序慢?

在浏览器中,多线程WebAssembly的速度比单线程慢,为什么?

为什么并行foreach循环实现比单线程慢?

C ++多线程性能比单线程代码慢

在C ++(VC ++ 2010 Express)上,双线程应用程序比单线程应用程序慢。怎么解决?

具有大量内存访问功能的多线程比单线程慢

Dijkstra算法OpenMP比单线程慢

Java是默认的单线程还是多线程?

单线程CPU上的多线程应用程序?

多线程图像处理比单线程慢?

使用多线程程序而不是使用单线程程序并行编译项目是否具有性能优势?

Python多处理比单线程慢

C ++多线程代码与单线程同时执行

javascript web workers 多线程字符串搜索比单线程慢?

ruby 中的多线程比单线程慢

单线程工作和多线程不工作

为什么我的多线程程序比单线程程序慢?

为什么多线程比单线程慢?(Linux,C,使用 pthread)