よくわかるHopscotch hashing
- 2. Locking!!!!
このアルゴリズムは
Lock-freeではありません!
Lock-freeを期待して見にきた方は回れ右!
- 3. Hashmapとは?
• みんな大好き連想配列!
– RubyでもPerlでもPythonでも人気者!
– C++でならunordered_map、JavaならHashMap
• 何かの値をキーとして別の値を保存・検索できるデータ構造
– 「山!」→「川!」
• とにかく高速!
– O(1)で動作するデータ構造
• 大量のデータを入れても検索速度が変わらないただ一つのデータ
構造
- 4. その仕組み
山! 8番目!
川!
Hash関数に通すだけで
保存or検索すべき場所が判明する!
- 13. 選べる探索バリエーション(併用不
可)
Liner Probing
Quadratic Probing
±1, 2, 4, 8, 16…
Double Hashing
±Hash(x)
- 14. Open Addressing
• 一つのHash値に対して配列上の複数の場所が該当しうるの
でOpenと名がつくんだと思う
• 利点
– キャッシュの局所性を生かせるので速い(特にLinear Probing)
– ポインタの分だけ省メモリ
• 欠点
– 削除時にはデータを消さずに削除フラグを立てて再利用させる
だけ
• データが存在している事そのものが「まだ配列の続きにあるかも
よ」という状態を表しているので完全に消しちゃうとマズい
• よって挿入・削除で密度が上がってくると入ってるデータが少な
い時でも検索・挿入・削除の性能がガタ落ちする
- 15. ベンチマーク比較
キ
ャ
ッ
シ
ュ
ミ
ス
頻
度
使用済み要素の割合
- 18. • 利点
Cuckoo Hashing
– 検索は2つの配列の一箇所ずつを探すだけなので高速
– 多少ハッシュ値が偏ってももう一つのハッシュ値が散れば問題
ない
• 欠点
– 密度に応じて挿入のコストが上がる
– 2つの配列を使う分メモリを食う
• チェインのポインタを持たなくてよいのでそんなに問題でないか
も
– 特性上、全体の半分が埋まったところで性能がガタ落ちする
• タチが悪いと円環して終わらない事もあり得るのかな
– つまり半分埋まる前に拡大する必要がある
• スッカスカのテーブルを維持しなきゃいけないからありがたみ少
ない
- 23. 検索
• チェインハッシュで言うところのこれと状態は同じ
– 一つのバケット位置の下に複数のアイテムがぶら下がる
– 配列に連続している分、左のHopscotchのほうがキャッシュ
ヒット率が高い
1 アイテム アイテム 11001010
2 アイテム
3 アイテム 12 3 4
4 アイテム
- 27. 挿入
• およそ8ワード分のビット数先のバケットまで配列を舐めな
がら、アイテムが入っていない空バケットが無いかを探す
– 空バケットとはHop情報部分はともかくアイテム部分が空の物
• 空バケットをswapしながら左に移動させていく
– バケットからHop情報で飛べる1wordビット範囲でしかswapは
しない アイテム
01010100
ここに入れたいけ
ど空きが無い
ビッシ
リ swap
- 28. 挿入
• およそ8ワード分のビット数先のバケットまで配列を舐めな
がら、アイテムが入っていない空バケットが無いかを探す
– 空バケットとはHop情報部分はともかくアイテム部分が空の物
• 空バケットをswapしながら左に移動させていく
– バケットからHop情報で飛べる1wordビット範囲でしかswapは
しない アイテム
00010110
ここに入れたいけ
ど空きが無い
ビッシ
リ swap完了
- 29. 挿入
• およそ8ワード分のビット数先のバケットまで配列を舐めな
がら、アイテムが入っていない空バケットが無いかを探す
– 空バケットとはHop情報部分はともかくアイテム部分が空の物
• 空バケットをswapしながら左に移動させていく
– バケットからHop情報で飛べる1wordビット範囲でしかswapは
しない
• 挿入したい位置から1word幅になるまで続ける
ここに入れたいけ
ど空きが無い
ビッシ
リ swap
- 30. 挿入
• およそ8ワード分のビット数先のバケットまで配列を舐めな
がら、アイテムが入っていない空バケットが無いかを探す
– 空バケットとはHop情報部分はともかくアイテム部分が空の物
• 空バケットをswapしながら左に移動させていく
– バケットからHop情報で飛べる1wordビット範囲でしかswapは
しない
• 挿入したい位置から1word幅になるまで続ける
ここに入れたいけ
ど空きが無い
ビッシ
リ swap完了
- 35. ポイント
• バケットそれぞれにアイテムとHop情報が入っている。
– Hash値を算出して配列の該当部分にアクセスした瞬間に、その
周辺もキャッシュラインに同時に載るためキャッシュミスが減
る
• 検索時は必ずそのバケットから1wordのbit数以内の距離にあ
る
– カッコウハッシュはバケット2つしか1つのアイテムが入りうる
候補が無かったのに対して、1word幅bit個まで候補が増えてい
る
• 配列を拡張しなくても入る量が多い
• そんなわけで実装してみた。Boost::unordered_mapより速
い。
– https://gist.github.com/2943289