openMP 用于循环增量语句处理
openMP for loop increment statment handling
for (uint i = 0; i < x; i++) {
for (uint j = 0; j < z; j++) {
if (inFunc(p, index)) {
XY[2*nind] = i;
XY[2*nind + 1] = j;
nind++;
}
}
}
这里 x = 512 和 z = 512,nind = 0 最初和 XY[2*x*y]。
我想使用 openMP 为循环优化它,但"nind"变量与 for 循环紧密串行绑定。我不知道,因为我也在检查一个条件,所以有时它不会进入,如果和会跳过增量,或者它会进入增量 nind。 openMP 线程将增加 nind 变量,因为先到先将增加 nind 变量。有没有办法解绑它。("绑定"我的意思是只能串行实现(。
在这种情况下,典型的缓存友好解决方案是收集专用数组中的(i,j)
对,然后在末尾连接这些私有数组,最后根据需要对结果进行排序:
#pragma omp parallel
{
uint myXY[2*z*x];
uint mynind = 0;
#pragma omp for collapse(2) schedule(dynamic,N)
for (uint i = 0; i < x; i++) {
for (uint j = 0; j < z; j++) {
if (inFunc(p, index)) {
myXY[2*mynind] = i;
myXY[2*mynind + 1] = j;
mynind++;
}
}
}
#pragma omp critical(concat_arrays)
{
memcpy(&XY[2*nind], myXY, 2*mynind*sizeof(uint));
nind += mynind;
}
}
// Sort the pairs if needed
qsort(XY, nind, 2*sizeof(uint), compar);
int compar(const uint *p1, const uint *p2)
{
if (p1[0] < p2[0])
return -1;
else if (p1[0] > p2[0])
return 1;
else
{
if (p1[1] < p2[1])
return -1;
else if (p1[1] > p2[1])
return 1;
}
return 0;
}
您应该在 schedule(dynamic,N)
子句中试验不同的N
值,以便在开销(对于较小的 N
值(和负载不平衡(对于较大的 N
值(之间实现最佳权衡。比较函数compar
可能可以用更优化的方式编写。
这里的假设是合并和排序数组的开销很小。情况是否如此取决于许多因素。
这是Hristo Iliev的好答案的变体。
这里要操作的重要参数是货币对的索引,而不是货币对本身。
我们可以为每个线程并行填充对索引的私有数组。 每个线程的数组将被排序(与调度无关(。
以下函数合并两个排序数组
void merge(int *a, int *b, int*c, int na, int nb) {
int i=0, j=0, k=0;
while(i<na && j<nb) c[k++] = a[i] < b[j] ? a[i++] : b[j++];
while(i<na) c[k++] = a[i++];
while(j<nb) c[k++] = b[j++];
}
这是剩余的代码
uint nind = 0;
uint *P;
#pragma omp parallel
{
uint myP[x*z];
uint mynind = 0;
#pragma omp for schedule(dynamic) nowait
for(uint k = 0 ; k < x*z; k++) {
if (inFunc(p, index)) myP[mynind++] = k;
}
#pragma omp critical
{
uint *t = (uint*)malloc(sizeof *P * (nind+mynind));
merge(P, myP, t, nind, mynind);
free(P);
P = t;
nind += mynind;
}
}
然后给定一个指数k
P
该货币对(k/z, k%z)
。
合并可以改进。现在它O(omp_get_num_threads())
,但它可以在O(log2(omp_get_num_threads()))
完成。我没有为此烦恼。
Hristo Iliev 指出,动态调度并不能保证每个线程的迭代次数单调增加。 我认为在实践中它们是,但原则上不能保证。
如果要 100% 确定迭代单调增加,则可以手动实现动态调度。
您提供的代码看起来像是尝试按顺序填充 XY 数据。在这种情况下,OMP 多线程可能不是该作业的工具,因为线程(在最佳情况下(应尽可能避免通信。你可以引入一个原子计数器,但话又说回来,按顺序做可能会更快。
另外,您希望通过优化它来实现什么?x 和 z 不是太大,所以我怀疑即使你以并行方式重新表述你的问题,你也会得到实质性的速度提升。
如果你确实想要并行执行 - 将你的索引映射到数组,例如(未测试,但应该测试(
#pragma omp parallel for shared(XY)
for (uint i = 0; i < x; i++) {
for (uint j = 0; j < z; j++) {
if (inFunc(p, index)) {
uint idx = (2 * i) * x + 2 * j;
XY[idx] = i;
XY[idx + 1] = j;
}
}
}
但是,您的阵列 XY 中会有间隙。这对您来说可能是也可能不是问题。
- 有人可以解释一下吗?这是关于数组和数组内部 if 语句的一些处理
- 在 if 语句中处理多个 or 的更优雅的方法是什么
- 如何处理托管C++ (/CLR) 中 #using 语句中的错误
- 如果/else-if语句将如何处理此操作
- 谁能帮我处理C++中的语句和字符串
- 可以使用switch语句处理的最大事例数
- openMP 用于循环增量语句处理
- 如何设置错误处理语句的格式
- C++中的错误处理-试图返回到指定的语句
- 如何处理鼠标点击逻辑的许多嵌套if语句
- c++编译器如何处理在条件语句中声明的类型
- 使用If语句处理布尔值
- libneo4j_client. c++中的预处理语句
- 为什么c++中的if语句不能处理多个条件
- 这段c++代码是如何处理不寻常的单个布尔语句的?
- 构造函数的function-try-block处理程序中的返回语句
- 组织sqlite3 C/ c++预处理语句(避免全局代码混乱)
- 编译时断言,当并非所有枚举值都在 C++ 的 switch 语句中处理时
- 包含预处理指令的多行宏语句
- MySQL连接器中的预处理语句