多线程mex代码比单线程慢

时间:2012-09-28 12:20:50

标签: c++ multithreading matlab mex

我在MATLAB中编写mex代码来执行和操作(因为该操作在c ++中使用了库)。 mex代码有一个部分,其中有一个函数在具有不同参数值的循环中重复调用,并且每个函数调用是独立的(即,1个调用的计算不依赖于先前的调用)。因此,为了加快速度,我编写了多线程代码来创建多个线程 - 确切的线程数等于循环迭代次数,在我的示例中,此值为10.每个线程在循环中计算单个值的函数参数,线程返回和连接,完成一些更多的计算并返回结果。 所有这些在理论上应该给我很好的加速,但我看到多线程代码比普通的单线程代码慢很多!!我可以使用非常强大的24核机器,所以这完全令人费解,因为我希望每个线程都安排在一个单独的核心上。 有什么想法导致这个?导致这种情况的代码中的任何常见问题/错误?

非常感谢任何帮助。

编辑: 为了回答人们在这里提出的解决方案中提出的许多疑问,我想分享一些关于我的代码的信息: 1.每个函数调用都需要几分钟,因此线程的同步和产生不应该是一个开销(尽管如果在这种情况下有任何缓解情况,任何有关它的信息都会非常有用!)

  1. 每个线程都访问公共数据结构,数组,矩阵,但这些中的值根本不会被覆盖。对变量的所有写操作都是对线程本地的变量,指针,数组等进行的。所以,我猜这里不应该有很多缓存未命中?

  2. 我的代码中也没有互斥锁部分,因为没有线程写入任何公共内存位置。所有写入都是针对线程本地的内存位置。

  3. 我还在试图找出我的多线程实现无效的原因:(所以,任何指针/信息都会非常有用!

    谢谢!

3 个答案:

答案 0 :(得分:1)

您没有描述您的代码所做的事情,所以这只是猜测。

多线程不是奇迹般的治疗方法。多线程有很多方法,单线程代码块可能比原始代码慢。产生,同步,连接和销毁线程涉及大量开销。

假设手头的任务是添加十对数字。如果通过为每次添加生成一个线程然后在计算完成时加入和销毁来制作这个多线程,那么多线程版本将比原始版本慢得多。线程不适用于非常短的持续时间计算。产生,加入和销毁的成本将通过并行执行这些简单任务而超过您获得的任何加速。

使事情变慢的另一种方法是建立阻碍并行操作的障碍。例如,一个互斥锁,用于防止多个写入者同时访问同一个对象。受保护的代码需要很小。使线程的整个主体在互斥体的幌子下运行,并且您具有相当于单线程应用程序的功能,该应用程序添加了大量的线程开销。

即使您没有将并行执行放在适当的位置,也可能存在妨碍并行执行的障碍。其中一些障碍在C标准库中。 POSIX要求大多数库函数都是线程安全的。该标准仅列出了不必是线程安全的函数。如果在这些计算中使用库函数,那么最好保持单线程,因为您的代码本质上是单线程的。

答案 1 :(得分:1)

考虑到你的问题有多普遍,一般的答案是可能有两种影响:

  • 启动和停止线程(以及同步它们)涉及大量开销,并且计算扩展不足以克服开销。每个函数调用的总次数将为这个问题提供一些启示。
  • 线程可以相互竞争并降低总体性能。一种常见的机制是“缓存颠簸”。由于多个内核共享相同的内存控制器和部分缓存层次结构,因此一个线程可以使用所需的信息填充缓存,只是为了让一些数据被不同线程的需要驱逐,导致更多的主内存访问。由于主内存访问非常昂贵,最终结果是放缓。

我会用不同数量的线程来测试这个工作。例如,可能结果是使用两个线程是有利的,但是四个或更多线程不是。有关更详细的答案,请在问题中添加更多详细信息,例如计算类型,数据集大小等。

答案 2 :(得分:1)

我认为你的问题根本不是特定的 - 在为SMP编写多线程代码时,这听起来像是常见的性能问题。

为已经提到的潜在问题添加一些内容:

  • False cache line sharing:您可能认为您的线程独立工作,而实际上它们访问同一缓存行中的不同数据。琐碎的例子:

    /* global variable accessible by all threads */
    int thread_data[nthreads];
    
    /* inside thread function */
    thread_data[thrid] = some_value;
    
  • 低效的内存带宽利用率。在NUMA系统上,您希望CPU访问自己的数据库。如果未正确分发数据,CPU会向其他CPU请求内存。这意味着沟通,你不怀疑它是在那里。

  • 线程亲和力。有点连接到上面的要点。您希望线程在整个计算过程中绑定到自己的CPU。否则它们可能会被操作系统迁移,这会导致开销,并且可能会远离他们将访问的内存库。