parallel-processing - 关于 OpenMP 部分和关键部分的问题
问题描述
我正在尝试制作一个快速的并行循环。在循环的每次迭代中,我构建了一个成本高昂的数组,因此我希望它分布在多个线程上。构建数组后,我用它来更新矩阵。在这里它变得很棘手,因为矩阵对所有线程都是通用的,所以只有 1 个线程可以一次修改矩阵的一部分,但是当我处理矩阵时,事实证明我也可以分配这项工作,因为我可以处理不同的部分同时矩阵。
这是我目前正在做的事情:
#pragma omp parallel for
for (i = 0; i < n; ++i)
{
... build array bi ...
#pragma omp critical
{
update_matrix(A, bi)
}
}
...
subroutine update_matrix(A, b)
{
printf("id0 = %d\n", omp_get_thread_num());
#pragma omp parallel sections
{
#pragma omp section
{
printf("id1 = %d\n", omp_get_thread_num());
modify columns 1 to j of A using b
}
#pragma omp section
{
printf("id2 = %d\n", omp_get_thread_num());
modify columns j+1 to k of A using b
}
}
}
问题是 update_matrix() 例程的两个不同部分没有被并行化。我得到的输出如下所示:
id0 = 19
id1 = 0
id2 = 0
id0 = 5
id1 = 0
id2 = 0
...
所以这两个部分由同一个线程(0)执行。我尝试在主循环中删除#pragma omp critical,但它给出了相同的结果。有谁知道我做错了什么?
解决方案
#pragma omp parallel sections
不应该在那里工作,因为您已经在该#pragma omp prallel for
子句分发的代码的并行部分中。除非您使用 启用嵌套并行化,否则omp_set_nested(1);
该parallel sections
子句将被忽略。
请注意,它不一定是有效的,因为产生新线程会产生开销成本,如果该update_matrix
部分不是太 CPU 密集型,则可能不值得。
你有几个选择:
把它给忘了。如果循环的非关键部分确实需要进行大多数计算,并且您已经拥有与 CPU 一样多的线程,那么为简单的操作生成额外的线程将没有好处。只需删除
parallel sections
子例程中的子句。尝试启用嵌套
omp_set_nested(1);
另一种选择是以双倍同步开销为代价的,将使用命名临界区。ONE_TO_J 部分可能只有一个线程,
critical
J_TO_K 部分可能只有一个线程,critical
因此基本上最多两个线程可以并行更新矩阵。这在同步开销方面是昂贵的。#pragma omp parallel for for (i = 0; i < n; ++i) { ... build array bi ... update_matrix(A, bi); // not critical } ... subroutine update_matrix(A, b) { printf("id0 = %d\n", omp_get_thread_num()); #pragma omp critical(ONE_TO_J) { printf("id1 = %d\n", omp_get_thread_num()); modify columns 1 to j of A using b } #pragma omp critical(J_TO_K) { printf("id2 = %d\n", omp_get_thread_num()); modify columns j+1 to k of A using b } }
如果合适的话,或者使用原子操作来编辑矩阵。
#pragma omp parallel for for (i = 0; i < n; ++i) { ... build array bi ... update_matrix(A, bi); // not critical } ... subroutine update_matrix(A, b) { float tmp; printf("id0 = %d\n", omp_get_thread_num()); for (int row=0; row<max_row;row++) for (int column=0;column<k;column++){ float(tmp)=some_function(b,row,column); #pragma omp atomic A[column][row]+=tmp; } }
顺便说一句,数据在 C 中以行主要顺序存储,因此您应该逐行而不是逐列更新矩阵。这将防止错误共享并提高算法的内存访问性能。
推荐阅读
- javascript - 使用 Intersection Observer API 检测可滚动 div 中最顶层的元素
- php - 在 Magento 2 中,哪些 crons 将维护设置为启用?
- vb.net - 如何在不依赖 XMLInclude 的情况下在派生类上使用 XML 序列化?
- html - 即使将值更正为有效,自定义验证消息仍然显示无效
- python - 如何使用 Python 创建时间线视觉显示支线分支
- python - 如何在 Gurobi addMConstr 中组合多个术语?
- sql - 如何将“nextval('testing_thing_thing_id_seq'::regclass)”声明为 postgres 表“testing_thing”中列“thing_id”的默认值?
- python - 使用python在hadoop中实现DGIM算法?
- quarkus - AWS Lambda 前面的 Kongo 插件,用于休息 api
- java - 如何获取以 C# 开头的 Java 程序的实时输入/输出