微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 OpenMP 多线程比单线程慢很多 系统语言时间函数代码我如何编译代码数据大小时间函数单线程结果OpenMP 的结果代码使用并行使用parallel for 和omp critical

如何解决使用 OpenMP 多线程比单线程慢很多 系统语言时间函数代码我如何编译代码数据大小时间函数单线程结果OpenMP 的结果代码使用并行使用parallel for 和omp critical

我正在尝试使用 OpenMP 并行我的 C++ 神经网络训练过程。但它不起作用。
然后我使用带有嵌套循环的简单 C++ 代码来测试 OpenMP。
但是 OpenMP 多线程比单线程慢得多。
我做错了什么让它变慢了吗?还是我错过了什么?

系统

MacOS 4 核

语言

C++

时间函

我同时使用了 high_resolution_clock::Now()omp_get_wtime()

  1. std::chrono::high_resolution_clock::Now();

单线程花费时间:0.00000000000000
2 个线程花费时间:0.00010013580322
4 个线程花费时间:0.00016403198242
6 个线程花费时间:0.00017309188843
8 个线程花费时间:0.00112605094910
10 个线程花费时间:0.00013613700867
12 个线程花费时间:0.00082898139954

  1. omp_get_wtime();

单线程花费时间:0.00000005900000
2 个线程花费时间:0.00009907600000
4 个线程花费时间:0.00018207300000
6 个线程花费时间:0.00014479500000
8 个线程花费时间:0.00070604400000
10 个线程花费时间:0.00057277700000
12 个线程花费时间:0.00074358000000

代码

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

using namespace std;
void test() {
    int j = 0;
    for (int i = 0; i < 100000; i++) {
        // do something to kill time...
        j++;
    }
};

int main()
{
    auto startTime = chrono::high_resolution_clock::Now();
    auto endTime = chrono::high_resolution_clock::Now();

    // without openMp
    startTime = chrono::high_resolution_clock::Now();
    for (int i = 0; i < 100000; i++) {
        test();
    }
    endTime = chrono::high_resolution_clock::Now();
    chrono::duration<double> diff = endTime - startTime;
    cout << setprecision(14) << fixed;
    cout << "single thread cost time: " << diff.count() << endl;

    // 2 threads
    startTime = chrono::high_resolution_clock::Now();
    #pragma omp parallel for num_threads(2)
    for (int i = 0; i < 100000; i++) {
        test();
    }
    endTime = chrono::high_resolution_clock::Now();
    diff = endTime - startTime;
    cout << "2 threads cost time: " << diff.count() << endl;

    // 4 threads
    startTime = chrono::high_resolution_clock::Now();
    #pragma omp parallel for num_threads(4)
    for (int i = 0; i < 100000; i++) {
        test();
    }
    endTime = chrono::high_resolution_clock::Now();
    diff = endTime - startTime;
    cout << "4 threads cost time: " << diff.count() << endl;

    // 6 threads
    startTime = chrono::high_resolution_clock::Now();
    #pragma omp parallel for num_threads(6)
    for (int i = 0; i < 100000; i++) {
        test();
    }
    endTime = chrono::high_resolution_clock::Now();
    diff = endTime - startTime;
    cout << "6 threads cost time: " << diff.count() << endl;

    startTime = chrono::high_resolution_clock::Now();
    #pragma omp parallel for num_threads(8)
    for (int i = 0; i < 100000; i++) {
        test();
    }
    endTime = chrono::high_resolution_clock::Now();
    diff = endTime - startTime;
    cout << "8 threads cost time: " << diff.count() << endl;

    startTime = chrono::high_resolution_clock::Now();
    #pragma omp parallel for num_threads(10)
    for (int i = 0; i < 100000; i++) {
        test();
    }
    endTime = chrono::high_resolution_clock::Now();
    diff = endTime - startTime;
    cout << "10 threads cost time: " << diff.count() << endl;

    startTime = chrono::high_resolution_clock::Now();
    #pragma omp parallel for num_threads(12)
    for (int i = 0; i < 100000; i++) {
        test();
    }
    endTime = chrono::high_resolution_clock::Now();
    diff = endTime - startTime;
    cout << "12 threads cost time: " << diff.count() << endl;

    // system("pause");
    return 0;
}

我如何编译代码

clang++ -std=c++11 -Xpreprocessor -fopenmp parallel.cpp -O3 -o parallel -lomp

更新

大家好,之前的问题已经解决了,我想我不应该使用 NUM_THREAD。

但是当我使用 OpenMP 来加速我的神经网络时,它需要更长的时间。

数据大小

MNIST 数据集,每个 epoch 60000

时间函

omp_get_wtime()

单线程结果

***** 训练纪元 1.
次数:6000。
批量大小:10.
进度:5999/6000。
火车时间是... 64.7082。
准确度:97.72% 9772/10000。
预测时间是... 3.51836.
正在发布数据样本...
释放神经网络...

OpenMP 的结果

***** 训练纪元 1.
次数:6000。
批量大小:10.
进度:5999/6000。
火车时间为:247.615。
准确度:97.72% 9772/10000。
预测时间为:30.739。

代码使用并行

#pragma omp parallel for
        for (int k = 0; k < size; k++) {
            layer->map[i].data[k] = activation_func::tan_h(layer->map_common[k] + layer->map[i].b);
            // cout << "current thread: " << omp_get_thread_num() << endl;
        }

使用parallel foromp critical

代码
for (int k = 0; k < layer->map_count; k++) {
        for (int i = 0; i < map_h; i++) {
            for (int j = 0; j < map_w; j++) {
                double max_value = prev_layer->map[k].data[2*i*upmap_w + 2*j];
                for (int n = 2*i; n < 2*(i + 1); n++) {
                    #pragma omp parallel for
                    for (int m = 2*j; m < 2*(j + 1); m++) {
                         #pragma omp critical
                        max_value = MAX(max_value,prev_layer->map[k].data[n*upmap_w + m]);
                    }
                }
                layer->map[k].data[i*map_w + j] = activation_func::tan_h(max_value);
            }
        }
    }

解决方法

我正在尝试使用并行我的 C++ 神经网络训练过程 开放式MP。但它不会工作。然后我使用了一个简单的 C++ 代码 用于测试 OpenMP 的嵌套循环。

我经常看到这种情况; 在代码中引入 OpenMP 或在这方面的并行性,不会神奇地使您的代码更快。

为什么??因为有很多因素,但是(在您的上下文中)因为并行完成的工作应该足够大以克服并行性的开销(例如线程创建、同步等)。为此,您需要增加并行任务的大小/数量。

另一个问题是您对代码进行基准测试的方式:

您的并行任务:

<div class="container">
    <h1>Stopwatch</h1>
    <h3>00:00</h3>
</div>
<div class="container">
    <button type="button">Start</button>
    <button type="button">Stop</button>
    <button type="button">Reset</button>
</div>

在顺序版本中,编译器可以轻松推断出void test() { int j = 0; for (int i = 0; i < 100000; i++) { // do something to kill time... j++; <---- Not enough work done in parallel } }; 。此外,因为您没有对该值执行任何操作( j = 100000 - 1;),编译器实际上可以优化对 j 函数的整个调用。因此,正如评论中指出的那样:

你的测试循环并没有真正做任何事情,所以编译器可能是 删除它。 那么你得到的时间将主要是花费的时间 创建线程。 – 1201ProgramAlarm

测试函数应该返回值并且你的代码应该打印 它在某处。 AS @1201ProgramAlarm 已经说过,编译器可能会检测到 您只是在浪费计算时间并删除循环。 – Michael 克莱姆

此外,不要使用以下代码块:

test()

复制了很多次,最好是一次并使用外部环境变量 // 2 threads startTime = chrono::high_resolution_clock::now(); #pragma omp parallel for num_threads(2) for (int i = 0; i < 100000; i++) { test(); } endTime = chrono::high_resolution_clock::now(); diff = endTime - startTime; cout << "2 threads cost time: " << diff.count() << endl; 更改线程数。

关于您的更新:

OMP_NUM_THREADS

for (int k = 0; k < layer->map_count; k++) { for (int i = 0; i < map_h; i++) { for (int j = 0; j < map_w; j++) { double max_value = prev_layer->map[k].data[2*i*upmap_w + 2*j]; for (int n = 2*i; n < 2*(i + 1); n++) { #pragma omp parallel for for (int m = 2*j; m < 2*(j + 1); m++) { #pragma omp critical max_value = MAX(max_value,prev_layer->map[k].data[n*upmap_w + m]); } } layer->map[k].data[i*map_w + j] = activation_func::tan_h(max_value); } } } 基本上是使代码顺序化。实际上比顺序更糟糕,因为有锁定机制的额外开销。

您应该使用 OpenMP reduce 而不是 critical section,这正是适用于这种情况的。此外,您可以尝试并行化 #pragma omp critical

for (int n = 2*i; n < 2*(i + 1); n++)

  1. 就个人而言,请不要误会,但我认为您应该先花更多时间学习多线程和 OpenMP 的基础知识,然后再尝试盲目并行化代码。

  2. 请不要继续添加对原始问题的更新,以及更新的问题。只需创建一个新问题即可。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?