基本的 openmp 程序运行速度较慢
basic openmp program runs slower
我正在努力使我的程序 运行 更快,所以我将使用并行计算。在此之前,我尝试了简单的 for 循环,但它 运行 更慢。
打开 mp 之前:
int a[100000] = { 0 };
clock_t begin = clock();
for (int i = 0; i < 100000; i++)
{
a[i] = i;
}
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
printf("%lf", elapsed_secs);
打开 mp 后:
int a[100000] = { 0 };
clock_t begin = clock();
#pragma omp parallel for
for (int i = 0; i < 100000; i++)
{
a[i] = i;
}
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
printf("%lf", elapsed_secs);
要成功使用您的第一个 OpenMP 并行(多线程)代码示例,您需要从以下两个角度改进您的测试用例:
使您的示例可测试。为此:
- 确保您的代码足够复杂,不会让编译器有任何机会 "optimize" 整个循环结束(即防止编译器有点用单个表达式替换整个循环)
- 您最终可能需要引入函数包装循环并在运行时将参数传递给此函数(通过 argc/argv)以使编译器感到困惑,同时保持代码非常简单
- 确保使用正确的编译标志(-O2 -fopenmp 用于 GCC,其他一些标志用于其他编译器)
- 确保你的循环需要足够的时间,并且你使用正确的方法来衡量在循环中花费的时间(其他受访者,包括 Gilles,已经很好地指出了这一点)
确保你的循环在每次循环迭代中做足够的(理想的计算)工作(即加法、乘法等),以便各种 开销 与在 OpenMP 运行时库内部进行一些幕后工作相关(需要在线程之间进行 "schedule"/plan/distribute 迭代) 不是 "bigger" 比 有用的工作量 在你的循环迭代中完成。
第二和第三维基百科 OpenMP' parallel for examples 已经足够好,可以满足给定的标准(虽然您的示例不满足)。您正处于仅遵循维基百科示例将帮助您获得一些基本理解的地步。
学习给定的基础知识后,您的下一步将是 (a) 理解 "Data Races" / "Race Conditions" / "Loop Carried Dependencies" 和 (b) 理解 # 之间的 "difference" pragma omp parallel 和#pragma omp for(同样,您需要从书籍或基础 OpenMP 课程中找到简单示例)。
(老实说,所有其他主题,例如 OpenMP 不平衡、动态与静态、内存带宽,只有在您花费至少几天 reading/practicing 来了解更简单的概念后才会有意义)
你说你的代码运行速度比较慢,其实你并不知道。原因是你使用clock()
来测量时间,而这个函数统计了当前线程的CPU时间,可能还有一个它产生的所有线程。为了评估加速,您需要测量的是 经过的挂钟时间 。为此,OpenMP 为您提供 omp_get_wtime()
。尝试在您的代码中使用它,然后您就会真正了解您的代码是否从 OpenMP 中获得任何好处。
现在,让我们明确一点,您的代码只不过是写入内存。因此,您很有可能很快就会使内存带宽饱和。因此,除非您有多个内存控制器,否则在这种情况下您不太可能从添加线程中获益良多。请看看this answer说服自己。
最后,请确保在退出代码之前对数据进行了一些处理,否则,编译器可能只是对其进行了优化,导致代码几乎什么都不做(但速度非常快) .
我正在努力使我的程序 运行 更快,所以我将使用并行计算。在此之前,我尝试了简单的 for 循环,但它 运行 更慢。
打开 mp 之前:
int a[100000] = { 0 };
clock_t begin = clock();
for (int i = 0; i < 100000; i++)
{
a[i] = i;
}
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
printf("%lf", elapsed_secs);
打开 mp 后:
int a[100000] = { 0 };
clock_t begin = clock();
#pragma omp parallel for
for (int i = 0; i < 100000; i++)
{
a[i] = i;
}
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
printf("%lf", elapsed_secs);
要成功使用您的第一个 OpenMP 并行(多线程)代码示例,您需要从以下两个角度改进您的测试用例:
使您的示例可测试。为此:
- 确保您的代码足够复杂,不会让编译器有任何机会 "optimize" 整个循环结束(即防止编译器有点用单个表达式替换整个循环)
- 您最终可能需要引入函数包装循环并在运行时将参数传递给此函数(通过 argc/argv)以使编译器感到困惑,同时保持代码非常简单
- 确保使用正确的编译标志(-O2 -fopenmp 用于 GCC,其他一些标志用于其他编译器)
- 确保你的循环需要足够的时间,并且你使用正确的方法来衡量在循环中花费的时间(其他受访者,包括 Gilles,已经很好地指出了这一点)
确保你的循环在每次循环迭代中做足够的(理想的计算)工作(即加法、乘法等),以便各种 开销 与在 OpenMP 运行时库内部进行一些幕后工作相关(需要在线程之间进行 "schedule"/plan/distribute 迭代) 不是 "bigger" 比 有用的工作量 在你的循环迭代中完成。 第二和第三维基百科 OpenMP' parallel for examples 已经足够好,可以满足给定的标准(虽然您的示例不满足)。您正处于仅遵循维基百科示例将帮助您获得一些基本理解的地步。
学习给定的基础知识后,您的下一步将是 (a) 理解 "Data Races" / "Race Conditions" / "Loop Carried Dependencies" 和 (b) 理解 # 之间的 "difference" pragma omp parallel 和#pragma omp for(同样,您需要从书籍或基础 OpenMP 课程中找到简单示例)。
(老实说,所有其他主题,例如 OpenMP 不平衡、动态与静态、内存带宽,只有在您花费至少几天 reading/practicing 来了解更简单的概念后才会有意义)
你说你的代码运行速度比较慢,其实你并不知道。原因是你使用clock()
来测量时间,而这个函数统计了当前线程的CPU时间,可能还有一个它产生的所有线程。为了评估加速,您需要测量的是 经过的挂钟时间 。为此,OpenMP 为您提供 omp_get_wtime()
。尝试在您的代码中使用它,然后您就会真正了解您的代码是否从 OpenMP 中获得任何好处。
现在,让我们明确一点,您的代码只不过是写入内存。因此,您很有可能很快就会使内存带宽饱和。因此,除非您有多个内存控制器,否则在这种情况下您不太可能从添加线程中获益良多。请看看this answer说服自己。
最后,请确保在退出代码之前对数据进行了一些处理,否则,编译器可能只是对其进行了优化,导致代码几乎什么都不做(但速度非常快) .