【问题标题】:Parallelizing radix sort for floating point numbers using pthread library in C使用 C 中的 pthread 库并行化浮点数的基数排序
【发布时间】:2021-10-10 16:34:17
【问题描述】:

我正在尝试使用 C 语言使用 POSIX 线程并行化基数排序。特长是需要为浮点数实现基数排序。目前,代码是按顺序运行的,但我不知道如何并行化代码。谁能帮我这个?任何帮助表示赞赏。

【问题讨论】:

  • 你试过什么?你遇到了什么问题?请注意,您并不是真的在问问题。作为参考,另请阅读How to Ask

标签: c multithreading sorting pthreads radix-sort


【解决方案1】:

基数排序很难在 CPU 上有效地并行化。基数排序有两个部分:直方图的创建和桶填充

要并行创建直方图,您可以在每个线程中填充局部直方图,然后对直方图执行(基于树的)缩减以构建全局直方图。只要直方图相对于每个线程计算的数据块很小,这种策略就可以很好地扩展。并行化此步骤的另一种方法是使用原子添加直接填充共享直方图。当线程写入访问冲突(这通常发生在小直方图和许多线程上)时,最后一种方法几乎无法扩展。请注意,在这两种解决方案中,输入数组在线程之间是均匀分布的。

关于桶填充部分,一种解决方案是利用原子添加来填充桶:每个桶需要1个原子计数器,以便每个线程可以安全地推回项目。此解决方案仅在线程不经常访问同一个存储桶(存储桶冲突)时进行扩展。这个解决方案不是很好,因为算法的可扩展性强烈依赖于输入数组的内容(在最坏的情况下是连续的)。有一些解决方案可以减少线程之间的冲突(更好的可伸缩性),但代价是更多的工作(线程较少时速度较慢)。一种是从两侧填充桶:ID 为偶数的线程按升序填充桶,ID 为奇数的线程按降序填充桶。请注意,考虑虚假共享以最大限度地提高性能非常重要。

【讨论】:

  • 当两个或更多线程访问同一个缓存行而不是同一个存储桶时,原子添加会受到影响。运行这些线程的独立内核之间的缓存一致性通常基于缓存行。为了避免这种情况,线程可以生成局部直方图,然后退出(除一个线程外),然后可以添加局部直方图以形成单个直方图。
  • 确实,这就是我最后一句话的重点(关于虚假分享)。减少错误共享影响的一种解决方案是在桶之间使用填充。另一种解决方案是使用随机化。最先进的算法似乎使用基于树的原子减少和弱共享直方图(参见 OpenMP 运行时,如 IOMP)。可悲的是,没有一种方法真的很棒。
  • 正如我的回答中提到的,对于 T 个线程,将数组拆分为 T 个部分并生成 T 个直方图,然后将它们转换为 T 个存储桶起始索引数组,至少使该部分并行化。然后,您可以使用 T/2 线程对索引求和,然后使用 T/4 线程对结果求和,...,最后一个线程来生成最终的索引数组。
【解决方案2】:

一种简单的并行化基数排序的简单方法是使用最高有效位 (MSD) 通道将数组拆分为多个 bin,然后可以同时对每个 bin 进行排序。这种方法依赖于值的某种均匀分布,至少在最高有效位方面是这样,以便这些 bin 的大小合理地相等。

例如,使用 8 位(基数为 256)的数字大小,使用 MSD 通道将数组拆分为 256 个 bin。假设有 t 个线程,则一次对 t 个 bin 进行排序,使用最低有效位优先基数排序。

对于较大的数组,使用较大的初始数字大小将数组拆分为更多的 bin 可能会有所帮助,目的是使 t 个 bin 适合缓存。

链接到非并行基数排序,该排序使用 MSD 进行第一遍,然后使用 LSD 进行接下来的 3 遍。 RadixSort() 结束时对 256 个 bin 进行排序的循环可以并行化:

Radix Sort Optimization

对于第一遍,您可以使用 Jerome Richard 回答中的并行方法,但根据数据模式,由于缓存和内存冲突,它可能没有太大帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-05
    • 1970-01-01
    相关资源
    最近更新 更多