阻塞操作的成本增加了线程数

时间:2012-10-02 01:01:59

标签: c multithreading optimization

我编写了一个执行某些计算然后合并结果的程序
我使用多线程并行计算
在合并结果阶段,每个线程将锁定全局数组,然后将单个部分附加到其中,并且将进行一些额外的工作以消除重复。

我测试它并发现合并的成本随着线程的数量而增加,并且速率是出乎意料的:

2个主题:40,116,084(我们)
6线程:511,791,532(us)

原因:当线程数增加时会发生什么?我该怎么改变呢?

--------------------------斜线---------------------- -------------------------------

实际上,代码非常简单,有伪代码:

typedef my_object {
长没有;
int count;
双重值;
//别人的东西
} my_object_t;

static my_object_t ** global_result_array; //大约十

static pthread_mutex_t global_lock;

void * thread_function(void * arg){
my_object_t ** local_result;
int local_result_number;
int i;
my_object_t * ptr;
为(;;){
if(exit_condition){return NULL;}
if(merge_condition){
//开始时间点到日志
pthread_mutex_lock(& global_lock);
for(i = local_result_number-1; i> = 0; i ++){
ptr = local_result [i];
if(NULL == global_result_array [ptr-> no]){
global_result_array [ptr-> no] = ptr; //步骤4
其他{
global_result_array [ptr-> no] - > count + = ptr-> count; //步骤5
global_result_array [ptr-> no] - >值+ = ptr->值; //步骤6
}
}
pthread_mutex_unlock(& global_lock); //结束时间点到日志
其他{
//做一些计算并产生部分和线程局部的结果,即local_result和local_result_number
}
}
}


如上所述,两个线程和六个线程之间的差异是步骤5和步骤6,我已经计算出步骤5和6的执行顺序约为数亿个。其他线程相同。
因此,从我的观点来看,合并操作非常简单,尽管使用了2个线程或6个线程,但它们都需要锁定并完全合并。
另一个令人惊讶的事情是:当使用六线程时,第4步的成本很高!这是导致总成本激增的原因!
顺便说一句:测试服务器有两个cpu,每个cpu有四个核心。

3 个答案:

答案 0 :(得分:1)

显示的行为有多种原因:

  1. 更多线程意味着更多的锁和线程之间更多的阻塞时间。从您的描述中可以明显看出,您的实现使用互斥锁或类似的东西。如果数据集在很大程度上是独占的,那么使用线程加速会更好。

  2. 除非您的系统拥有与线程数一样多的处理器/核心,否则它们都无法同时运行。您可以使用pthread_setconcurrency设置最大并发数。

答案 1 :(得分:0)

上下文切换是一种开销。因此差异。如果您的计算机有6个核心,它会更快。过度需要为线程提供更多的上下文切换。

答案 2 :(得分:0)

这是2/6线程之间的巨大性能差异。对不起,但你必须非常努力地做出这么大的差异。你似乎成功了:((

正如其他人所指出的那样,如果花在线程间通信上的时间(锁等)小于并发操作所获得的时间,那么在一个数据集上使用多个线程只会变得有价值。

例如,如果您发现要连续合并较小的数据部分(例如,使用合并排序),则可以有效地优化线程间通信和缓存抖动所浪费的时间。这就是为什么一旦将数据划分为小于L1缓存大小的块,就会经常以就地排序启动多线程合并排序。

'每个线程都将锁定全局数组' - 尽量不要这样做。长时间锁定大型数据结构,或者连续短时间锁定它们是一个非常糟糕的计划。锁定全局一旦序列化线程并生成一个具有太多线程间通信的线程。连续锁定/释放会生成一个线程,其中包含太多,非常多的线程间通信。

一旦操作变得如此之短以至于返回被减少到无用点,那么最好将这些操作排队到一个完成工作的线程。

锁定经常被过度使用和/或误用。如果我发现自己锁定任何东西的时间超过推动/弹出指针到队列或类似的时间,我开始变得紧张......

没有看到/分析代码,更重要的是数据,(我猜两者都很复杂),很难给出任何直接的建议:(