下面是一段从R运行的C代码,用于将矩阵的每一行与矢量进行比较。相同值的数量存储在两列矩阵的第一列中。
我知道可以很容易地在R中完成它(就像检查结果一样),但这是更复杂用例的第一步。
当不使用openmp时,它可以正常工作。当使用openmp时,它会给出相关(0.99)但结果不一致。
问题1:我在做什么错了?
Question2:我使用double for循环用零填充输出矩阵(ret)。有什么更好的解决方案?
此外,在包装中使用代码时,也观察到不一致之处。我试图使用inline
使代码可重现,但是它无法识别openmp语句(我试图在cfunction
的参数中包括'omp.h',...)。
问题3:我们如何使此代码与inline
一起使用?
在这个话题上,我(太过远了)。
library(inline)
compare <- cfunction(c(x = "integer", vec = "integer"), "
const int I = nrows(x), J = ncols(x);
SEXP ret;
PROTECT(ret = allocMatrix(INTSXP, I, 2));
int *ptx = INTEGER(x), *ptvec = INTEGER(vec), *ptret = INTEGER(ret);
for (int i=0; i<I; i++)
for (int j=0; j<2; j++)
ptret[j * I + i] = 0;
int i, j;
#pragma omp parallel for default(none) shared(ptx, ptvec, ptret) private(i,j)
for (j=0; j<J; j++)
for (i=0; i<I; i++)
if (ptx[i + I * j] == ptvec[j]) {++ptret[i];}
UNPROTECT(1);
return ret;
")
N = 3e3
M = 1e4
m = matrix(sample(c(-1:1), N*M, replace = TRUE), nc = M)
v = sample(-1:1, M, replace = TRUE)
cc = compare(m, v)
cr = rowSums(t(t(m) == v))
all.equal(cc[,1], cr)
答案 0 :(得分:0)
由于上面的评论,我重新考虑了数据竞赛问题。
IIUC,我的循环在j
(各列)上并行化。然后,每个线程都有自己的i
值(行),但是各个线程可能具有相同的值,然后试图同时增加ptret[i]
。
为了避免这种情况,我现在首先在i
上循环,以便只有一个线程将增加每一行。
然后,我意识到我可以在第一个循环内移动ptret
的零初始化。
它似乎有效。我得到了相同的结果,增加了CPU使用率,并在笔记本电脑上加快了3-4倍的速度。
我想这可以解决问题1和2。我将仔细研究inline / openmp问题。
下面的代码,一遍。
#include <omp.h>
#include <R.h>
#include <Rinternals.h>
#include <stdio.h>
SEXP c_compare(SEXP x, SEXP vec)
{
const int I = nrows(x), J = ncols(x);
SEXP ret;
PROTECT(ret = allocMatrix(INTSXP, I, 2));
int *ptx = INTEGER(x), *ptvec = INTEGER(vec), *ptret = INTEGER(ret);
int i, j;
#pragma omp parallel for default(none) shared(ptx, ptvec, ptret) private(i, j)
for (i = 0; i < I; i++) {
// init ptret to zero
ptret[i] = 0;
ptret[I + i] = 0;
for (j = 0; j < J; j++)
if (ptx[i + I * j] == ptvec[j]) {
++ptret[i];
}
}
UNPROTECT(1);
return ret;
}