#排序 #迭代器 #外部

extsort-iter

适用于所有类型和迭代器的外部排序

5个不稳定版本

0.3.1 2023年9月30日
0.3.0 2023年8月30日
0.2.1 2023年5月28日
0.2.0 2023年5月28日
0.1.0 2022年9月24日

算法中排名第279

每月下载量23

MIT许可证

80KB
2K SLoC

extsort-iter license Rust docs.rs Crates.io

只要数据能适应您的磁盘,就能对任何类型的迭代器进行排序!

extsort-iter是一个库,允许您对外部排序任何迭代器,无需进行序列化步骤。

从概念上讲,我们正在使用缓冲区接收您的输入迭代器,对运行进行排序,在将数据流回之前将其移动到磁盘。

为什么使用这个crate?

因为我们提供了一个非常出色的高级API,并且在没有任何(反)序列化开销的情况下执行排序。

用法

let data = [1,42,3,41,5];

// lets pretend this is an iterator that will not fit in memory completely
let source = data.into_iter(); 
let config = ExtsortConfig::default();
let iterator = data.external_sort(config);

// do whatever you want with the sorted iterator
for item in iterator { 
    println!("{}", item);
}

// alternatively you can provide a comparison function
// (here one that sorts 42 to the beginning because it is the best number)
let iterator = data.external_sort_by(config, |a,b| if a == 42 {
    Ordering::Less
}else {
    a.cmp(b)
});

// or you can provide a key extraction function to sort by
// (here we are sorting by the number of trailing ones)
let iterator = data.external_sort_by_key(config, |a| a.trailing_ones());

// if you can spare the memory, you should increase the size of the in-memory sort buffer.
// it defaults to 10MB.
// larger buffer sizes will drastically improve your sort performance, because only the
// in-memory sort part is parallelized and the IO becomes more sequential
let config = ExtsortConfig::with_buffer_size(1_073_741_824);

如果您启用了parallel_sort功能,所有排序函数的并行版本都将可用,这些并行版本将使用rayon并行排序运行缓冲区

// normal sort by the ord impl
let iterator = data.par_external_sort(config);

// sort using a comparison function
let iterator = data.par_external_sort_by(config, |a,b| if a == 42 {
    Ordering::Less
}else {
    a.cmp(b)
});

// parallel sort using key extraction function
let iterator = data.par_external_sort_by_key(config, |a| a.trailing_ones());

如果您启用了compress_lz4_flex功能,您可以在I/O目的上启用数据的透明压缩

let config = ExtsortConfig::default().compress_lz4_flex();

// and then just sort as normal
let iterator = data.par_external_sort(config);

何时不使用这个crate

当您的源迭代器很大时,因为每个项目都拥有大量堆内存。这意味着以下情况会导致内存耗尽

let data = "somestring".to_owned();
let iterator = std::iter::from_fn(|| Some(data.clone())).take(1_000_000);
let sorted  = iterator.external_sort(ExtsortConfig::default_for::<String>());

原因是我们在结果迭代器产出之前不会丢弃源迭代器的值。

您可以将它视为缓冲整个输入迭代器,其中值本身位于磁盘上,但所有指向值的内存仍位于堆上。

不安全的使用

此crate使用不安全代码将运行缓冲区视为字节数组以将其复制到磁盘,并将数据从磁盘读回到内存中,然后再次将其作为我们的值处理。

所有不安全的代码都限制在 file_run 模块中,文档编写得相当好,并且经过测试,使用 miri 运行测试套件通过,所以我们尽可能地确保代码的正确性和稳定性。

依赖项

~0–310KB