algorithm - 如果数据不适合物理 RAM 内存,最快排序?
问题描述
我希望在具有 8-128 个内核、10% 元素的 RAM 以及提供 100-1000 MBytes/s 的磁盘的系统上对 10 亿到 1000 亿个元素的列表进行排序。
我测试了一个简单的合并排序,其中每个合并由 CPU 并行执行:
sorted_part_a:__
\__[CPU.1]__
sorted_part_b:__/ \
\__[CPU.5]__
sorted_part_c:__ / \
\__[CPU.2]__/ \
sorted_part_d:__/ \
\__[CPU.7]
sorted_part_e:__ /
\__[CPU.3]__ /
sorted_part_f:__/ \ /
\__[CPU.6]__/
sorted_part_g:__ /
\__[CPU.4]__/
sorted_part_h:__/
但这有一个问题,即最后的合并步骤 [ CPU.7
] 在合并最后两个输入时必须在单个核心上进行 n 次比较,并且比较可能很昂贵(想想必须尊重语言环境设置的字符串)。在我的测试中 [ CPU.7
] 是瓶颈。
然后我研究了红黑树。它们有几个优点:
- 当树被构建时,得到一个排序列表是
O(n)
没有比较的。这避免了我在合并排序测试中看到的瓶颈。 - 您可以并行构建树并并行合并它们,从而使用多个内核。
- 在开始构建树之前您不需要所有数据(因此,如果您正在从慢速设备读取,则可以在读取时进行排序,从而不会浪费挂钟时间)。
将树保存到磁盘似乎也很容易(只需导出排序列表和树的高度),但只从磁盘返回树的一部分似乎更棘手。
我已阅读哪种并行排序算法具有最佳的平均案例性能?但它似乎忽略了中等大小数据的常见情况:该数据适合服务器的磁盘,但它不适合 RAM。
给定硬件(8-128 个内核,10% 的元素的 RAM,以及提供 100-1000 MBytes/s 流式传输的磁盘,1000 iops)什么是对 10^9 到 100 * 10^9 的列表进行排序的最快方法每个 10-100 字节的元素?
通俗地说:
在单个服务器上对最大数量的数据进行快速排序的可靠方法是什么?
解决方案
当我没有定制软件来为我完成繁重的工作时,我从来不需要做这种事情。
但我在 Google 时的标准解决方案是将你的初始数据存储在分布式文件系统中,进行分布式合并排序,并将最终数据存储在分布式文件系统中。由于最终排序的数据结构存储在块中,这意味着即使在最后一遍中,每个 CPU 也只需在其块内进行比较,从而在整个过程中允许 CPU 完全使用。
对于大型数据集,基本上从来没有一个用例需要您在一个地方一次将它放在一个地方,您必须迭代整个事物。相反,施加这种任意限制只会造成不必要的瓶颈。
推荐阅读
- go - 为什么 vet 抱怨这个变量已声明但未使用?
- office-js - 为什么 office-js 不允许一些明显的事情——比如发送电子邮件,或者附加到消息的末尾?
- swift - 通过 KeyPath / WritableKeyPath 快速初始化
- javascript - 兑换
转换成 JSON - python - 用于查找具有笛卡尔符号规则的多项式的正实根数的python函数
- javascript - 通过 Vue Router 传递自定义 JS 对象
- flutter - flutter / auto_route 中的动态多个嵌套路由
- apple-m1 - Sencha Architect 4.3 for M1 芯片
- shopify - Robots.txt(允许)
- java - 每次创建新对象时如何在Java中增加类变量中的数字?