我正在尝试学习如何使用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 :(得分:1)
您忽略了提到您正在使用的编译器和OpenMP实现。我会猜测你正在使用其中一个,比如PGI,它不会自动假设在默认并行区域中创建的线程数,除非要求这样做。由于您没有指定编译器,我不能确定这些选项实际上会对您有所帮助,但对于PGI的编译器,在编译和链接可执行文件时,必要的选项是-mp=allcores
。添加后,它将导致系统为并行区域为每个核心创建一个线程,这些并行区域不指定线程数或设置适当的环境变量。
默认情况下,使用从omp_get_num_procs获取的数字来设置线程数的限制,但不一定是创建的数量。如果要动态设置创建的数字,请在运行应用程序之前将环境变量OMP_NUM_THREADS
设置为所需的数字,它应该按预期运行。
答案 1 :(得分: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;
}
答案 2 :(得分: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
请注意&#34;用户&#34;时间超过&#34; Real&#34;时间,表示负载分布在该机器上可用的核心8上,效率约为80%。通过更多工作,您可以进一步改进,但即使使用这个简单版本,我们也会看到使用的核心不止一个(在64核机器上,我们应该看到至少50个:比单线程代码有1个改进,可能比这更好一些。)
答案 3 :(得分:0)
我看到你的代码唯一的问题是当你输出时你需要把它放在critcal
部分,否则多个线程可以同时写入同一行。
请参阅我的代码更正。
就一个帖子而言,我认为您可能会看到的是使用dynamic
。运行小数字的线程比运行大数字的线程快得多。当小数字的线程完成并获得另一个小数字列表运行时,它会快速完成,而大数字的线程仍在运行。这并不意味着你只运行一个线程。在我的输出中,我看到相同线程的长流,找到素数,但最终其他人报告。您还将卡盘大小设置为1000
,因此,如果您仅运行超过1000个数字,则循环中将只使用一个线程。
在我看来,你正试图找到一个素数列表或素数的总和。你正在使用试验部门。这比使用“Eratosthenes的筛子”效率低得多。
以下是Eratosthenes的筛选示例,它使用OpenMP在我的4核心系统上在不到一秒的时间内找到了前十亿个数字中的素数。 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;
}