我正在使用CUDA实现简单的冒泡排序算法,我有一个问题 我执行以下代码,以交换数组中的2个连续元素:
if(a[threadIdx.x]>a[threadIdx.x + 1])
Swap(a[threadIdx.x] , a[threadIdx.x + 1]);
请注意,块中的线程数是数组大小的一半。这是一个很好的实现吗?即使有分支,单个warp中的线程是否会并行执行?因此它实际上需要N次迭代才能对数组进行排序?
还要注意我知道我可以实现更好的排序算法,我可以使用Thrust,CUDPP或SDK中的样本排序算法,但在我的情况下,我只需要一个简单的算法来实现。
答案 0 :(得分:2)
我假设:
如果其中任何一个不成立,请不要进行冒泡排序!
块中的线程数是数组大小的一半。这是一个很好的实现吗?
这是合理的。当在warp中出现发散分支时,所有线程都以完美同步的方式执行所有分支,只需要一些线程将其标记设置为“disabled”。这样,每个分支只执行一次。唯一的例外 - 当没有来自warp的线程占用分支时 - 那么只是跳过分支。
BUG!
在您的代码中,我看到了一个问题。如果您希望一个线程对数组的两个元素进行操作,请让它们专门处理它,即:
if(a[2*threadIdx.x]>a[2*threadIdx.x + 1])
Swap(a[2*threadIdx.x] , a[2*threadIdx.x + 1]);
否则,如果Swap
由两个相邻线程执行,则某些值可能会消失,而其他一些值可能会在数组中重复。
另一个错误!
如果您的块大于经线尺寸,请记得在需要时放置__syncthreads()
。即使您的块较小(不应该),您应该检查__threadfence_block()
以确保对同一块的其他线程可以看到对共享内存的写入。否则,编译器可能在优化方面过于激进并使您的代码无效。
另一个问题
如果您修复了第一个错误,您的共享内存将出现双向存储库冲突。它不是非常重要,但您可能希望重新组织数组中的数据以避免它们,例如按以下顺序包含连续元素:
[1,3,5,7,9,...,29,31,2,4,6,8 ......,30,32]
这样,元素1和2属于共享内存中的同一个库。
答案 1 :(得分:1)
我很高兴你意识到GPU上的冒泡排序可能会非常糟糕!我正在努力弄清楚如何获得足够的并行性而无需启动许多内核。此外,当你完成后,你可能很难解决问题。
无论如何,要回答你的具体问题:是的,在这种情况下你很可能会出现扭曲分歧。但是,鉴于“else”分支实际上是空的,这不会减慢你的速度。平均而言(直到此列表被排序),warp中大约一半的线程将采用“if”分支,其他线程将等待,然后当“if”分支完成时,warp线程可以恢复为脚背。这远非您最大的问题:)