2013-06-19 76 views
0

我想了解如何使用openmp进行多线程。 这里是我的代码:Openmp无法自动创建线程

#include <iostream> 
#include <math.h> 
#include <omp.h> 
//#include <time.h> 
//#include <cstdlib> 

using namespace std; 

bool isprime(long long num); 

int main() 
{ 
     cout << "There are " << omp_get_num_procs() << " cores." << endl; 
     cout << 2 << endl; 
     //clock_t start = clock(); 
     //clock_t current = start; 
     #pragma omp parallel num_threads(6) 
     { 
     #pragma omp for schedule(dynamic, 1000) 
     for(long long i = 3LL; i <= 1000000000000; i = i + 2LL) 
     { 
       /*if((current - start)/CLOCKS_PER_SEC > 60) 
       { 
         exit(0); 
       }*/ 
       if(isprime(i)) 
       { 
         cout << i << " Thread: " << omp_get_thread_num() << endl; 
       } 
     } 
     } 
} 

bool isprime(long long num) 
{ 
     if(num == 1) 
     { 
       return 0; 
     } 
     for(long long i = 2LL; i <= sqrt(num); i++) 
     { 
       if (num % i == 0) 
       { 
         return 0; 
       } 
     } 
     return 1; 
} 

的问题是,我想的OpenMP基于多少个核心都可以自动创建多个线程。如果我取出num_threads(6),那么它只使用1个线程,但omp_get_num_procs()正确输出64.

如何获得此工作?

回答

0

我不知道我是否正确理解你的问题,但似乎你几乎在那里。你的意思是这样的:

#include <omp.h> 
#include <iostream> 

int main(){ 

    const int num_procs = omp_get_num_procs(); 
    std::cout<<num_procs; 

#pragma omp parallel for num_threads(num_procs) default(none) 
    for(int i=0; i<(int)1E20; ++i){ 
    } 

    return 0; 

} 
0

除非我相当严重错误的,正常的OpenMP序列化I/O(至少在一个流),所以这可能是您的问题所产生的至少一部分。删除从环路,并按摩了一下,其余的(没有多大意义在并行,直到你有合理有效的串行代码的工作),我结束了这样的事情:

#include <iostream> 
#include <math.h> 
#include <omp.h> 

using namespace std; 

bool isprime(long long num); 

int main() 
{ 
    unsigned long long total = 0; 

    cout << "There are " << omp_get_num_procs() << " cores.\n"; 

    #pragma omp parallel for reduction(+:total) 
    for(long long i = 3LL; i < 100000000; i += 2LL) 
     if(isprime(i)) 
      total += i; 

    cout << "Total: " << total << "\n"; 
} 

bool isprime(long long num) { 
    if (num == 2) 
     return 1; 
    if(num == 1 || num % 2 == 0) 
     return 0; 
    unsigned long long limit = sqrt(num); 

    for(long long i = 3LL; i <= limit; i+=2) 
     if (num % i == 0) 
      return 0; 
    return 1; 
} 

这不打印出线程数,但时间是我得到的是这样的:

Real 78.0686 
User 489.781 
Sys  0.125 

注意一个事实,即“用户”时间超过6倍那么大“真实”时,表明负载分发穿过该机器上可用的核心8,效率约为80%。多花点功夫,你可能会进一步改进,但即使使用这个简单的版本,我们也看到使用的核心数量不止一个(在64核机器上,我们应该看到至少50:1的改进通过单线程代码,并可能比这更好)。

0

我在代码中看到的唯一问题是,当您执行输出时,您需要将它放在critcal部分,否则多个线程可以同时写入同一行。
看我的代码更正。

就一条线索而言,我认为您可能会看到的是使用dynamic。运行在小数字上的线程要比运行大数量的线程快得多。当具有小数字的线程完成并且获得另一个小数字列表以便运行时,它又快速完成,而具有大数字的线程仍在运行。这并不意味着你只能运行一个线程。在我的输出中,我看到同一线程的长流发现了质数,但最终还是有其他人报告。您还将卡盘尺寸设置为1000,所以如果您例如只运行了1000个数字,则循环中只会使用一个线程。

它在我看来就像你试图找到一个素数列表或总数的素数。你正在使用试用部门。这比使用“Eratosthenes筛”效率低得多。

这是一个Eratosthenes的筛子的例子,它在我的4核心系统中使用OpenMP在不到一秒的时间内发现了十亿个数字中的素数。 http://create.stephan-brumme.com/eratosthenes/

我清理了你的代码,但没有尝试优化任何东西,因为算法效率低下。

int main() { 
    //long long int n = 1000000000000; 
    long long int n = 1000000; 
    cout << "There are " << omp_get_num_procs() << " cores." << endl; 
    double dtime = omp_get_wtime(); 
    #pragma omp parallel 
    { 
     #pragma omp for schedule(dynamic) 
     for(long long i = 3LL; i <= n; i = i + 2LL) { 
      if(isprime(i)) { 
       #pragma omp critical 
       { 
        cout << i << "\tThread: " << omp_get_thread_num() << endl; 
       } 
      } 
     } 
    } 
    dtime = omp_get_wtime() - dtime; 
    cout << "time " << dtime << endl; 
} 
1

您忽略了提及您正在使用哪种编译器和OpenMP实现。我会猜测你正在使用其中的一个,例如PGI,它不会自动假设在默认并行区域中创建的线程数,除非被要求这样做。既然你没有指定编译器,我不能确定这些选项实际上对你有帮助,但是对于PGI的编译器,在编译和链接可执行文件时必要的选项是-mp=allcores。随着增加,它会导致系统为每个核心创建一个线程,用于没有指定线程数量或设置适当环境变量的并行区域。

您从omp_get_num_procs获得的数字默认用于设置线程数限制,但不一定是创建的数量。如果要动态设置创建的编号,请在运行应用程序之前将环境变量OMP_NUM_THREADS设置为所需的编号,并且其行为应与预期相符。