如何解决使用 OpenMP 多线程比单线程慢很多 系统语言时间函数代码我如何编译代码数据大小时间函数单线程结果OpenMP 的结果代码使用并行使用parallel for 和omp critical
我正在尝试使用 OpenMP 并行我的 C++ 神经网络训练过程。但它不起作用。
然后我使用带有嵌套循环的简单 C++ 代码来测试 OpenMP。
但是 OpenMP 多线程比单线程慢得多。
我做错了什么让它变慢了吗?还是我错过了什么?
系统
MacOS 4 核
语言
C++
时间函数
我同时使用了 high_resolution_clock::Now() 和 omp_get_wtime()。
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
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 for 和omp 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++)
-
就个人而言,请不要误会,但我认为您应该先花更多时间学习多线程和 OpenMP 的基础知识,然后再尝试盲目并行化代码。
-
请不要继续添加对原始问题的更新,以及更新的问题。只需创建一个新问题即可。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。