2012-08-16 78 views
0

我是新来使用conditional_variables,所以我可以很容易在这里做一些愚蠢的事情,但我使用boost线程而不是直接调用函数时,我得到了一些奇怪的表现。如果我将func上创建boost线程的那一行改为直接调用func,那么代码运行速度会快几个数量级。我已经使用升压线程池软件起飞源锻造的尝试和它没有什么区别...性能差与助推条件互斥

下面是代码:

#include <boost/thread.hpp> 


using namespace boost; 

condition_variable cond; 
mutex conditionalMutex; 
int numThreadsCompleted = 0; 
int numActiveThreads = 0; 

void func() 
{ 
    { 
    lock_guard<mutex> lock(conditionalMutex); 
    --numActiveThreads; 
    numThreadsCompleted++; 
    } 
    cond.notify_one(); 
}; 


int main() 
{ 
    int i=0; 
    while (i < 100000) 
    { 
     if (numActiveThreads == 0) 
     { 
      ++numActiveThreads; 
      thread thd(func); 
      //Replace above with a direct call to func for several orders of magnitude 
      //performance increase... 
      ++i; 
     } 
     else 
     { 
      unique_lock<mutex> lock(conditionalMutex); 
      while (numThreadsCompleted == 0) 
      { 
       cond.wait(lock); 
      } 
      numThreadsCompleted--; 
     } 
    } 
    return 0; 
} 

回答

0

你创建和销毁线程,这通常是因为一些实施较低级别的OS构造,通常是某种轻量级的过程。这种创造和销毁可能是昂贵的。

最后,你基本上做

  1. 创建线程
  2. 等待线程来一遍又一遍退出

。这意味着创建/销毁,而且你每次都在做,所以成本会增加。

+0

我想创建和销毁线程将是问题的开销也让我尝试threadpools:只有boost :: thread 34秒,线程池7秒和函数调用.16秒。这是在增加循环长度以给出更大的数字之后... – 2012-08-16 02:17:15

0

除了创建和销毁线程的开销之外,branch prediction可能会影响性能的差异。

不必穿线,if语句总是正确的,因为numActiveThreads0在每次循环的起点和终点:

while (i < 100000) 
{ 
    if (numActiveThreads == 0) // branch always taken 
    { 
    ++numActiveThreads; // numActiveThreads = 1 
    func();    // when this returns, numActiveThreads = 0 
    ++i;     
    } 
} 

这导致:

  • 分支预测从来没有失败。
  • 线程创建/销毁没有任何开销。
  • 没有花时间阻止等待获取conditionalMutex

对于线程,numActiveThreads在顺序迭代中可以是或不是0。在我测试的大多数机器上,都观察到短的可预测模式,每次迭代时if-statement和else-statement之间交替分支。但是,有时if语句是在顺序迭代中选择的。因此,时间可能会浪费在:

  • 分支预测失败。
  • 线程的创建和销毁。如果创建和销毁是并发的,则可能会在底层线程库中发生同步。
  • 阻止等待获取conditionMutex或等待cond
+0

理论上,分支预测惩罚不应该是导致性能下降的重要因素。一个分支上的错过预测通常花费少于100个周期,而线程创建和销毁可能更耗费CPU。 – WiSaGaN 2012-08-17 10:43:03

1

性能必须比直接调用函数差得多。您启动一个线程,然后等待该线程结束。即使您将开始线程的开销减少到零,您也可以与该线程进行通信。而且你至少会有一个上下文切换,因为你的func()基本上什么都不做,所以开销会变成很大的因素。在func()中添加一些更多的有效载荷,比例将会改变。如果必须要做的事情很少,只需在发现此事的线程上完成。

顺便说一句:你有一个竞争条件,因为你写入numActiveThreads没有互斥被锁定。上面的代码归结为:

int main() 
{ 
    int i=0; 
    while (i < 100000) 
    { 
     thread thd(func); 
     thd.join(); 
     ++i; 
    } 

    return 0; 
} 

,有实在没有理由为什么这应该是快于:

int main() 
{ 
    int i=0; 
    while (i < 100000) 
    { 
     func(); 
     ++i; 
    } 

    return 0; 
}