首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Aparapi计算向量中的不同值

用Aparapi计算向量中的不同值
EN

Stack Overflow用户
提问于 2016-08-04 09:03:49
回答 1查看 247关注 0票数 2

我希望将熵函数与APARAPI并行实现。在这个函数中,我需要在向量中计数不同的键,但是它不能正确执行。

假设我们只有3个不同的值。这是我的密码:

代码语言:javascript
复制
final int[] V = new int[1024];
// Initialization for V values
final int[] count = new int[3];
Kernel kernel = new Kernel(){
    @Override
    public void run(){
        int gid = getGlobalId();
        count[V[gid]]++;
    }
};
kernel.execute(Range.create(V.length));
kernel.dispose();

运行此代码段后,当我打印count[]值时,它会给我1,1,1,1。似乎count[V[gid]]++对每个Vgid只执行1次。

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-12-29 12:46:10

这就是问题所在。++操作符实际上是一种三种操作:读取当前值、增量它、写入新值。在Aparapi中,可能有1024个GPU线程同时运行。这意味着,当值为0时,它们将读取该值,可能同时读取值,然后将其增量为1,然后所有1024个线程都将写入1。

您所要做的是称为Map-还原函数。你只是跳了很多步。您需要记住,Aparapi是一个没有线程安全性的系统,因此您必须编写算法来适应这种情况。这就是地图减少的地方,这里是如何做一个。我只是写了它,并把它添加到Aparapi存储库的新家,详情如下。

代码语言:javascript
复制
int size = 1024;
final int count = 3;
final int[] V = new int[size];

//lets fill in V randomly...
for (int i = 0; i < size; i++) {
    //random number either 0, 1, or 2
    V[i] = (int) (Math.random() * 3);
}

//this will hold our values between the phases.
int[][] totals = new int[count][size];

///////////////
// MAP PHASE //
///////////////
final int[][] kernelTotals = totals;
Kernel mapKernel = new Kernel() {
    @Override
    public void run() {
        int gid = getGlobalId();
        int value = V[gid];
        for(int index = 0; index < count; index++) {
            if (value == index)
                kernelTotals[index][gid] = 1;
        }
    }
};
mapKernel.execute(Range.create(size));
mapKernel.dispose();
totals = kernelTotals;

//////////////////
// REDUCE PHASE //
//////////////////
while (size > 1) {
    int nextSize = size / 2;
    final int[][] currentTotals  = totals;
    final int[][] nextTotals = new int[count][nextSize];
    Kernel reduceKernel = new Kernel() {
        @Override
        public void run() {
            int gid = getGlobalId();
            for(int index = 0; index < count; index++) {
                nextTotals[index][gid] = currentTotals[index][gid * 2] + currentTotals[index][gid * 2 + 1];
            }
        }
    };
    reduceKernel.execute(Range.create(nextSize));
    reduceKernel.dispose();

    totals = nextTotals;
    size = nextSize;
}
assert size == 1;

/////////////////////////////
// Done, just print it out //
/////////////////////////////
int[] results = new int[3];
results[0] = totals[0][0];
results[1] = totals[1][0];
results[2] = totals[2][0];

System.out.println(Arrays.toString(results));

请记住,虽然它看起来效率很低,但实际上它在大得多的数字上运行得很好。这个算法工作得很好

代码语言:javascript
复制
size = 1048576.

使用新的大小,下面的结果在我的系统上计算了大约一秒。

代码语言:javascript
复制
[349602, 349698, 349276]

最后一个注意事项是,您可能需要考虑迁移到aparapi.com中更活跃的项目。它包括对bug的几个修复,以及与前面链接的旧库相比的许多额外特性和性能增强。它还位于maven中心,大约有十几个版本。因此,它更容易使用。我刚刚在这个答案中编写了代码,但决定在新的Aparapi存储库的示例部分中使用它,您可以在新的Aparapi存储库中的以下链接上找到它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38762986

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档