0

I am trying to learn how to use openmp for multi threading. Here is my code:

#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;
}

The problem is that I want openmp to automatically create a number of threads based on how many cores are available. If I take out the num_threads(6), then it just uses 1 thread yet the omp_get_num_procs() correctly outputs 64.

How do I get this to work?

4

4 回答 4

1

您忽略了提及您正在使用的编译器和 OpenMP 实现。我猜你正在使用其中之一,比如 PGI,它不会自动假设在默认并行区域中创建的线程数,除非被要求这样做。由于您没有指定编译器,我无法确定这些选项是否真的会对您有所帮助,但对于 PGI 的编译器,必要的选项是-mp=allcores在编译和链接可执行文件时。添加后,它将导致系统为未指定线程数或未设置适当环境变量的并行区域为每个内核创建一个线程。

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

于 2013-06-20T10:13:08.767 回答
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 倍多,这表明负载以大约 80% 的效率分布在这台机器上可用的核心 8 上。多做一点工作,您也许可以进一步改进,但即使使用这个简单的版本,我们也看到使用的内核远不止一个(在您的 64 核机器上,我们应该看到至少 50:1 的改进超过单线程代码,并且可能比这更好)。

于 2013-06-19T20:44:28.553 回答
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;

}
于 2013-06-19T20:33:03.400 回答
0

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

就一个线程而言,我认为您可能会看到是由于使用dynamic. 运行在小数字上的线程比运行在大数字上的线程快得多。当具有小数字的线程完成并获得另一个要运行的小数字列表时,它会在具有大数字的线程仍在运行时再次快速完成。这并不意味着您只运行一个线程。在我的输出中,我看到同一线程的长流找到了素数,但最终其他人也报告了。您还将卡盘大小设置1000为,例如,如果您只运行超过 1000 个数字,则只有一个线程将在循环中使用。

在我看来,您正在尝试查找素数列表或素数的总和。您正在为此使用试用部门。这比使用“埃拉托色尼筛”效率低得多。

这是埃拉托色尼筛法的一个例子,它在我使用 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;
}
于 2013-06-20T05:35:10.063 回答