1个不稳定版本
使用旧的Rust 2015
0.0.1 | 2017年10月27日 |
---|
#15 在 #columnar
用于 column
23KB
462 行
Column
column
是一个Rust库,用于以列式格式表示特定类型的向量。当迭代大量元素但只需查看类型字段的子集时,列式表示很有用。
许可
根据以下任一许可授权
- Apache许可证2.0版,(LICENSE-APACHE 或 http://www.apache.org/licenses/LICENSE-2.0)
- MIT许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
供您选择。
贡献
除非您明确表示,否则任何旨在包含在本作品中的贡献,根据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,
}
过滤集合
当使用列式类型时,它们可能被传递到不同的下游功能,而不会公开集合中的所有元素。为了避免中间复制,这个crate包含一个过滤集合(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));
调试
列在编译过程中创建所需的实现。有时事情会出错,对生成的代码进行调试相当繁琐。因此,存在一个名为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 nightly运行,如下所示
% 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的字节数。然而,当所有数据都被接触,即所有列都必须加载时,这种加速可能微不足道,甚至可能是负的。此外,将基于行的表示形式转换为列表示形式还有一定的成本。
lib.rs
:
为结构体推导出一个Column
表示。
示例
#[macro_use] extern crate column_derive;
extern crate column;
#[derive(Column)]
struct Data {x: usize, y: u64}
依赖项
~1.7–3MB
~69K SLoC