1 个不稳定版本

使用旧的 Rust 2015

0.0.1 2017年10月27日

#13 in #列式

MIT/Apache

23KB
318

Column

column 是一个 Rust 库,用于以列式格式表示特定类型的向量。当迭代大量元素但仅查看类型字段的子集时,列式表示非常有用。

许可证

许可协议为以下之一:

任选其一。

贡献

除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交的任何贡献,均应如上所述双重许可,不附加任何额外的条款或条件。

示例

要使用 column,请将以下依赖项添加到项目 Cargo.toml

[dependencies]
column = { git = "https://github.com/antiguru/column-rs.git" }

这将从 Github 添加 column crate(这可能会改变!),这应该允许您在基于列的内存布局中使用常规结构体。

extern crate column;
#[macro_use] extern crate column_derive;

#[derive(Column, Debug)]
struct Data {
    id: usize,
    val: f64,
}

fn main() {
    let mut u = <Data as Column>::new();

    let ds = vec![Data { id: 0, val: 3.141 }, Data { id: 1, val: 42.}];
    u.extend(ds);

    for e in u.iter() {
        println!("Element: {:?}", e);
    }
    for mut e in u.iter_mut() {
        *e.val *= 2.;
    }
    for e in u.iter() {
        println!("Element: {:?}", e);
    }

}

此示例包含在 column crate 中,您可以通过在 crate 的根目录中键入以下内容来运行它

% cargo run --example columnar
Running `target/debug/examples/columnar`
Element: DataRef { id: 0, val: 3.141 }
Element: DataRef { id: 1, val: 42 }
Element: DataRef { id: 0, val: 6.282 }
Element: DataRef { id: 1, val: 84 }

泛型类型

生成的代码将值解引用以对 to_owned 材质化元素。这意味着值必须实现 Copy 特性才能使此操作生效。否则,Rust 将会报错。例如,这将产生一个可工作的泛型列式类型

#[derive(Column)]
struct DataGen<A: Copy> {
    id: A,
}

过滤集合

在使用列式类型时,它们可能在不公开集合中所有元素的情况下传递给不同的下游功能。为了避免中间复制,此 carte 包含一个过滤集合 (FilteredCollection)。它是一个围绕 &IntoIterator 结合一个存储目标集合中可用项的 Vec<bool> 的包装。

以下示例创建了一个 FilteredCollection 实例,并使用其 retain 方法仅保留集合中的子集元素。请注意,这不会更改底层数据。

use column::bitmap::FilteredCollection;
let mut bitmap_container = FilteredCollection::new(&container, container.len());
bitmap_container.retain(|u| p(u));

调试

在编译过程中,Column会创建所需的实现。有时事情会出错,生成的代码的调试相当繁琐。因此,存在一个标志verbose。它强制column将中间代码写入目标目录。对于一个类型Data,它将生成文件target/derive_column_Data.rs。(如果有更优雅的方式,请提出问题或发送拉取请求!)在Cargo.toml中插入以下片段以启用详细输出

[dependencies]
column = { git = "https://github.com/antiguru/column-rs.git", features = [ "verbose" ] }

此功能也可以在处理此项目时在命令行上激活。以下cargo调用测试并转储中间文件

cargo test --features verbose

性能

这里有一个小的基准测试。它表明,对于某些操作,列格式可以显著更快。使用Rust夜间版本运行它,如下所示

% rustup run nightly cargo bench
[...]
running 6 tests
test data_bitmap_column_add_assign   ... bench:  13,178,990 ns/iter (+/- 405,043) = 1909 MB/s
test data_bitmap_vec_add_assign      ... bench:  39,891,687 ns/iter (+/- 714,537) = 630 MB/s
test data_column                     ... bench:   1,949,104 ns/iter (+/- 79,882) = 4303 MB/s
test data_column_add_assign          ... bench:   5,495,641 ns/iter (+/- 203,841) = 4579 MB/s
test data_row                        ... bench:  16,817,910 ns/iter (+/- 264,722) = 498 MB/s
test data_row_add_assign             ... bench:  32,581,004 ns/iter (+/- 759,734) = 772 MB/s

test result: ok. 0 passed; 0 failed; 0 ignored; 6 measured; 0 filtered out

对性能数据进行评估时,请谨慎对待。使用列表示法获得的速度提升源于加载较少且更密集的数据到内存中。它只会显示在紧循环中不访问结构体所有元素时的好处,因为我们只有在那时才能减少传输到CPU的字节数。然而,当所有数据都被访问时,即所有列都必须加载时,速度提升可能微不足道,甚至可能为负。此外,将基于行的表示法转换为列表示法也有一定的成本。

依赖关系

~1.7–3MB
~68K SLoC