1

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

任何帮助将不胜感激。

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

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

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

我仍在试图找出我的多线程实现不起作用的原因:(所以,任何指针/信息都会非常有帮助!

谢谢!!

4

3 回答 3

1

我认为您的问题根本不是 mex 特有的——这听起来像是为 SMP 编写多线程代码时常见的性能问题。

补充一点已经提到的潜在问题:

  • 错误的缓存行共享:您可能认为您的线程独立工作,而实际上它们访问同一缓存行中的不同数据。简单的例子:

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

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

于 2012-09-28T13:32:34.860 回答
1

鉴于您的问题的普遍性,一般的答案是可能有两种影响:

  • 启动和停止线程(以及同步它们)有很大的开销,并且计算扩展不足以克服开销。每个函数调用的总次数将有助于解决这个问题。
  • 线程可以相互竞争并降低总体性能。一种常见的机制是“缓存抖动”。由于多个内核共享相同的内存控制器和部分缓存层次结构,一个线程可以用它需要的信息填充缓存,只是让一些数据被另一个线程的需要驱逐,导致更多的主内存访问。由于主存访问如此昂贵,最终结果是速度变慢。

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

于 2012-09-28T13:08:04.243 回答
1

你没有描述你的代码做了什么,所以这只是猜测。

多线程不是灵丹妙药。有很多方法可以使单线程代码块的多线程处理比原来的要慢。产生、同步、加入和销毁线程会产生大量开销。

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

另一种让事情变慢的方法是建立障碍以防止并行操作。例如,互斥体可防止多个写入者同时访问同一个对象。受保护的代码需要很小。让你的线程的整个主体在互斥锁的幌子下运行,你就相当于一个单线程应用程序,其中添加了一大堆线程开销。

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

于 2012-09-28T13:00:42.630 回答