Linux 下 openMP 效率并未提升的解决方案

  • OpenMP 正确观察计算时间
  • OpenMP 经验总结
    • (1) openmp 线程使用范围
    • (2)openmp 多层嵌套的问题

OpenMP 正确观察计算时间

在使用 openmp的过程中, 使用了简单的 #pragma omp parallel 但是观察计算时间并未得到优化

// 使用 openmp 优化的代码
#include 
#include  
#include 
#include 

int main(int argc, char **argv)
{
    int m = 1100;

    int a[m][m],i, j;

    int sum = 0;

    const clock_t begin_time = clock();

    omp_set_num_threads(4);

    double start = omp_get_wtime( );

    std::cout <<" NumThreads : "<< omp_get_max_threads()<<std::endl;

    #pragma omp parallel for private(j) reduction( +:sum)  // 将其注释即可观察不使用openmp的情况
    for(int k=0; k<100; k++)
    {
        for(int i=0; ifor (int j = 0; j < m; j++) 
            {
            sum = sum + 1;
            }
        }
        //std::cout << "Thread ID : " << omp_get_thread_num()<<"   sum : " << sum << std::endl;
    }

    double end = omp_get_wtime( );
    std::cout << "   sum  Total : " << sum << std::endl;

    std::cout << "Time clock(): "<< float( clock () - begin_time ) /  CLOCKS_PER_SEC << std::endl; 

    std::cout << "Time wtime(): "<< float( end - start )  << std::endl; 

    return 0;
}

使用 openmp优化的结果

 NumThreads : 4
   sum  Total : 121000000
   Time clock(): 0.278465

不使用openmp优化的结果

 NumThreads : 4
sum  Total : 121000000
Time clock(): 0.21804

可以看出, 不是用的效果甚至更好一些,但是这不符合常识啊。 经过测试原来发现正确的测量方法应该是使用 omp_get_wtime( ), 使用的代码如下。

#include  
#include 
#include 

int main(int argc, char **argv)
{
    int m = 1100;

    int a[m][m],i, j;

    int sum = 0;

    const clock_t begin_time = clock();

    omp_set_num_threads(4);

    double start = omp_get_wtime( );

    std::cout <<" NumThreads : "<< omp_get_max_threads()<<std::endl;

    #pragma omp parallel for private(j) reduction( +:sum) 
    for(int k=0; k<100; k++)
    {
        for(int i=0; ifor (int j = 0; j < m; j++) 
            {
            sum = sum + 1;
            }
        }
        //std::cout << "Thread ID : " << omp_get_thread_num()<<"   sum : " << sum << std::endl;
    }

    double end = omp_get_wtime( );
    std::cout << "sum  Total : " << sum << std::endl;

    std::cout << "Time clock(): "<< float( clock () - begin_time ) /  CLOCKS_PER_SEC << std::endl; 

    std::cout << "Time wtime(): "<< float( end - start )  << std::endl; 

    return 0;
}

最后的结果如下

 NumThreads : 4
sum  Total : 121000000
Time clock(): 0.280769
Time wtime(): 0.108388

解释一下, clock() 记录的是cpu的滴答数的,当并行多个进程同时计算, cpu滴答数成倍增加, 所以我们得到的差值并不是真实的时间数, openmp 提供的omp_get_wtime() 才记录的运行时的真实时间, 所以一直错误是没有正确的观察时间。 废了我两个小时解决。

OpenMP 经验总结

(1) openmp 线程使用范围

openmp是基于 “fork-join” 思想搭建的,在构造过程中。 不是很方便构造一个需要伴随着主线程运行的线程(不知道能不能叫做守护线程), 因为在工作中需要开出一个线程用于监听一个 信号, 我使用了 boost::thread 库中生成线程的方法

#include <boost/thread.hpp> 

new_thread_ = new boost::thread(boost::bind(&B::A, this));

void B::A() 
{
  while(ros::ok()) // 主要是监测这个
  {
    sleep(1); // 每隔 1s 检查一次

    if(Signal)  // updateMap_Signal 是全局更新地图的控制信号, 有两个地方可以发出信号;手都发出与定时更新
       {
        if(remap()) 
        {                   
            ROS_DEBUG("Updated");
        }
         Signal = 0;               
         }
  }
return;
}

这样产生的线程, 会伴随着 ros 运行时的状态, 直到主线程死亡。

(2)openmp 多层嵌套的问题

openmp 会根据cpu核心数目,fork处固定数目的线程, 如果产生了嵌套在线程切换过程中也消耗了时间, 此时反而可能拖累了执行的效率。 下面的例子有三个 for 循环, 分别检测一下他们的结果和执行效率。

#include  
#include 
#include 


int main(int argc, char **argv)
{
    int m = 1100;

    int a[m][m],i, j;

    int sum = 0;

    const clock_t begin_time = clock();

    omp_set_num_threads(4);

    double start = omp_get_wtime( );

    std::cout <<" NumThreads : "<< omp_get_max_threads()<<std::endl;

    #pragma omp parallel for private(j) reduction( +:sum) 
    for(int k=0; k<100; k++)
    {
        #pragma omp parallel for
        for(int i=0; i#pragma omp parallel for
            for (int j = 0; j < m; j++) 
            {
            sum = sum + 1;
            }
        }
        //std::cout << "Thread ID : " << omp_get_thread_num()<<"   sum : " << sum << std::endl;
    }

    double end = omp_get_wtime( );
    std::cout << "sum  Total : " << sum << std::endl;

    std::cout << "Time clock(): "<< float( clock () - begin_time ) /  CLOCKS_PER_SEC << std::endl; 

    std::cout << "Time wtime(): "<< float( end - start )  << std::endl; 

    return 0;
}
嵌套数 解释 时间
2 注释掉第三个 omp 0.189526
1 注释掉第二个和第三个 omp 0.098441

还有很多其它的测试, 但是这里也可以看出,只进行一个 omp 优化反而效率最高。

所以总结的策略是, 将 omp 放置在循环迭代次数最多的地方, 经过测试还发现,多线程的优化大概也就能提升 50% 的效率。 所以代码还是要写的漂亮才好 哈哈。

你可能感兴趣的:(C++)