OpenMP: 创建线程中的锁及原子操作性能比较

相关文档连接:
多核编程中的任务随机竞争模式的概率分析
多核编程中的任务分组竞争模式
多核编程中的负载平衡难题
多核编程中的锁竞争难题
多核编程的几个难题及其应对策略(难题一)
OpenMP并行程序设计(二)
OpenMP并行程序设计(一)
双核CPU上的快速排序效率

       在多核CPU中锁竞争到底会造成性能怎样的下降呢?相信这是许多人想了解的,因此特地写了一个测试程序来测试原子操作,windows CriticalSection, OpenMP的锁操作函数在多核CPU中的性能。

原子操作选用InterlockedIncrement来进行测试, 对每种锁和原子操作,都测试在单任务执行和多任务执行2000000次加锁解锁操作所消耗的时间。
测试的详细代码见后面。

测试机器环境: Intel 2.66G 双核CPU 机器一台

测试运行结果如下:
SingleThread, InterlockedIncrement 2,000,000: a = 2000000, time = 78
MultiThread, InterlockedIncrement 2,000,000: a = 2000000, time = 156
SingleThread, Critical_Section 2,000,000:a = 2000000, time = 172
MultiThread, Critical_Section, 2,000,000:a = 2000000, time = 3156
SingleThread,omp_lock 2,000,000:a = 2000000, time = 250
MultiThread,omp_lock 2,000,000:a = 2000000, time = 1063

在单任务运行情况下,所消耗的时间如下:
原子操作                        78ms
Windows CriticalSection   172ms
OpenMP 的lock操作         250ms

        因此从单任务情况来看,原子操作最快,Windows CriticalSection次之,OpenMP库带的锁最慢,但这几种操作的时间差距不是很大,用锁操作比原子操作慢了2~3倍左右。

在多个任务运行的情况下,所消耗的时间如下:

原子操作                 156ms
Windows CriticalSection 3156ms
OpenMP 的lock操作        1063ms

        在多任务运行情况下,情况发生了意想不到的变化,原子操作时间比单任务操作时慢了一倍,在两个CPU上运行比在单个CPU上运行还慢一倍,真是难以想象,估计是任务切换开销造成的。
        Windows CriticalSection则更离谱了,居然花了3156ms,是单任务运行时的18倍多的时间,慢得简直无法想象。
OpenMP的lock操作比Windows CriticalSection稍微好一些,但也花了1063ms,是单任务时的7倍左右。

       由此可以知道,在多核CPU的多任务环境中,原子操作是最快的,而OpenMP次之,Windows CriticalSection则最慢。

       同时从这些锁在单任务和多任务下的性能差距可以看出,,多核CPU上的编程和以往的单核多任务编程会有很大的区别。


测试代码如下:

#include <windows.h> #include <time.h> #include <process.h> #include <omp.h> #include <stdio.h>

void TestAtomic() {  clock_t t1,t2;  int      i = 0;  volatile LONG      a = 0;

 t1 = clock();

 for( i = 0; i < 2000000; i++ )  {   InterlockedIncrement( &a);  }

 t2 = clock();  printf("SingleThread, InterlockedIncrement 2,000,000: a = %ld, time = %ld\n", a, t2-t1);

 t1 = clock();

#pragma omp parallel for  for( i = 0; i < 2000000; i++ )  {   InterlockedIncrement( &a);  }

 t2 = clock();  printf("MultiThread, InterlockedIncrement 2,000,000: a = %ld, time = %ld\n", a, t2-t1); }

void TestOmpLock() {  clock_t t1,t2;  int i;  int a = 0;  omp_lock_t    mylock;

 omp_init_lock(&mylock);

 t1 = clock();

 for( i = 0; i < 2000000; i++ )  {   omp_set_lock(&mylock);   a+=1;   omp_unset_lock(&mylock);  }  t2 = clock();

 printf("SingleThread,omp_lock 2,000,000:a = %ld, time = %ld\n", a, t2-t1);

 t1 = clock();

#pragma omp parallel for  for( i = 0; i < 2000000; i++ )  {   omp_set_lock(&mylock);   a+=1;   omp_unset_lock(&mylock);  }  t2 = clock();

 printf("MultiThread,omp_lock 2,000,000:a = %ld, time = %ld\n", a, t2-t1);

 omp_destroy_lock(&mylock); }

 

void TestCriticalSection() {  clock_t t1,t2;  int i;  int a = 0;  CRITICAL_SECTION   cs;

 InitializeCriticalSection(&cs);

 t1 = clock();

 for( i = 0; i < 2000000; i++ )  {   EnterCriticalSection(&cs);   a+=1;   LeaveCriticalSection(&cs);  }  t2 = clock();

 printf("SingleThread, Critical_Section 2,000,000:a = %ld, time = %ld\n", a, t2-t1);

 t1 = clock();

#pragma omp parallel for  for( i = 0; i < 2000000; i++ )  {   EnterCriticalSection(&cs);   a+=1;   LeaveCriticalSection(&cs);  }  t2 = clock();

 printf("MultiThread, Critical_Section, 2,000,000:a = %ld, time = %ld\n", a, t2-t1);

 DeleteCriticalSection(&cs);

}

int main(int argc, char* argv[]) {

 TestAtomic();  TestCriticalSection();  TestOmpLock();

 return 0; }

结果:
OpenMP: 创建线程中的锁及原子操作性能比较_第1张图片

你可能感兴趣的:(OpenMP: 创建线程中的锁及原子操作性能比较)