この記事を書いたきっかけ
Rustのコードを読んでいたら
let mut connections = Slab::new();
このような記述が出てきて,ここ以外でもこのSlab
がでてきたので今日はこのSlab
について調べて,自分なりに理解できるようにまとめてみました。
まず,slab
クレートについて
slab
クレート
公式ドキュメントによると,
Pre-allocated storage for a uniform data type.
Slab provides pre-allocated storage for a single data type. If many values of a single type are being allocated, it can be more efficient to pre-allocate the necessary storage. Since the size of the type is uniform, memory fragmentation can be avoided. Storing, clearing, and lookup operations become very cheap.
While Slab may look like other Rust collections, it is not intended to be used as a general purpose collection. The primary difference between Slab and Vec is that Slab returns the key when storing the value.
It is important to note that keys may be reused. In other words, once a value associated with a given key is removed from a slab, that key may be returned from future calls to insert.
slab
は,ひとつの型に統一されたデータのための,プリアロケートされたストレージのことを指しているみたいです。
型の統一されたデータを管理する際はこのslab
を用いると,メモリフラグメンテーションを避けることができるので効率的にメモリ割り当てができるようです。
サンプルコード
公式ドキュメントに載っていたサンプルのコードです。
let mut slab = Slab::new();
let hello = slab.insert("hello");
let world = slab.insert("world");
assert_eq!(slab[hello], "hello");
assert_eq!(slab[world], "world");
slab[world] = "earth";
assert_eq!(slab[world], "earth");
最初にSlab::new()
でインスタンスを作成します。
slab.insert()
でデータをslab
に登録します。このときの戻り値がkeyになり,hello
変数やworld
変数に格納されるみたいな感じです。
これがslab
の基本的な使い方です。
vacant_entry
API
keyがinsert
よりも先に欲しい場合は,Slab::vacant_entry()
という関数を用いることができる。
let mut slab = Slab::new();
let hello = {
let entry = slab.vacant_entry();
let key = entry.key();
entry.insert((key, "hello"));
key
};
assert_eq!(hello, slab[hello].0);
assert_eq!("hello", slab[hello].1);
最初にslab.vacant_entry()
から返されたインスタンスをentry
変数に格納します。
そしてentry.key()
でまずkeyを生成しておきます。
そのあとentry.insert()
をする際に,先に取得しておいたkeyと一緒に値をメモリに割り当てて保管します。
Slab::with_capacity()
let mut slab = Slab::with_capacity(1024);
// ... use the slab
if slab.len() == slab.capacity() {
panic!("slab full");
}
slab.insert("the slab is not at capacity yet");
前もってslab
に割り当てる領域の大きさを定義しておくこともできます。
このサンプルのように,あらかじめ必要な大きさをきめておき,保管しているデータの量がキャパシティに達したらpanic!()
を実行する,ということもできます。
まとめ
slab
クレートは個人的にPoll
よりもとっかかりやすかったです。
型が絞られるなら可読性の向上にもつながると思ったので,積極的に使っていきたいです。
参考リンク
https://docs.rs/slab/0.4.2/slab/
https://raskr.hatenablog.com/entry/2018/04/22/175053
https://stackoverflow.com/questions/3770457/what-is-memory-fragmentation
https://k-onishi.hatenablog.jp/entry/2019/07/09/223222