【发布时间】:2014-07-22 18:54:15
【问题描述】:
因此,我正在尝试制作一个超轻量级、故意占用大量内存但速度非常快的哈希表,用于非常快速的查找,我不关心内存使用情况,也不关心它是否会犯一个罕见的错误。
基本上它只是创建一个巨大的数组(是数组,不是切片),使用修改后的 FNVa 哈希(修改为仅给出数组边界内的哈希)对字符串进行哈希处理,然后使用哈希保存或查找值数组索引。理论上,这应该是存储和检索 key=>value 对的最快方式。
这是我的基准:
package main
import (
"fmt"
"time"
)
const dicsize250 = 2097152000 // tested 115 collisions
type Dictionary250_uint16 struct {
dictionary [dicsize250]uint16
}
func (d *Dictionary250_uint16) Add(s string, v uint16) {
i := id(s,dicsize250)
d.dictionary[i]=v
return
}
func (d *Dictionary250_uint16) Delete(s string) {
i := id(s,dicsize250)
d.dictionary[i]=0
return
}
func (d *Dictionary250_uint16) Exists(s string) bool {
i := id(s,dicsize250)
if d.dictionary[i]==0 {
return false
} else {
return true
}
}
func (d *Dictionary250_uint16) Find(s string) uint16 {
i := id(s,dicsize250)
return d.dictionary[i]
}
// This is a FNVa hash algorithm, modified to limit to dicsize
func id(s string, dicsize uint64) uint64 {
var hash uint64 = 2166136261
for _, c := range s {
hash = (hash^uint64(c))*16777619
}
return hash%dicsize
}
var donothing bool
func main() {
dic := new(Dictionary250_uint16)
dic.Add(`test1`,10)
dic.Add(`test2`,20)
dic.Add(`test3`,30)
dic.Add(`test4`,40)
dic.Add(`test5`,50)
mc := make(map[string]uint16)
mc[`test1`]=10
mc[`test2`]=10
mc[`test3`]=10
mc[`test4`]=10
mc[`test5`]=10
var t1 uint
var t2 uint
var t3 uint
donothing = true
// Dic hit
t1 = uint(time.Now().UnixNano())
for i:=0; i<50000000; i++ {
if dic.Exists(`test4`) {
donothing = true
}
}
t3 = uint(time.Now().UnixNano())
t2 = t3-t1
fmt.Println("Dic (hit) took ",t2)
// Dic miss
t1 = uint(time.Now().UnixNano())
for i:=0; i<50000000; i++ {
if dic.Exists(`whate`) {
donothing = true
}
}
t3 = uint(time.Now().UnixNano())
t2 = t3-t1
fmt.Println("Dic (miss) took ",t2)
// Map hit
t1 = uint(time.Now().UnixNano())
for i:=0; i<50000000; i++ {
_,ok := mc[`test4`]
if ok {
donothing=true
}
}
t3 = uint(time.Now().UnixNano())
t2 = t3-t1
fmt.Println("Map (hit) took ",t2)
// Map miss
t1 = uint(time.Now().UnixNano())
for i:=0; i<50000000; i++ {
_,ok := mc[`whate`]
if ok {
donothing=true
}
}
t3 = uint(time.Now().UnixNano())
t2 = t3-t1
fmt.Println("Map (miss) took ",t2)
donothing = false
}
我得到的结果是:
Dic (hit) took 2,858,604,059
Dic (miss) took 2,457,173,526
Map (hit) took 1,574,306,146
Map (miss) took 2,525,206,080
基本上,我的哈希表实现比仅使用地图要慢得多,尤其是在命中时。我不明白这是怎么可能的,因为map 是一个重型实现(相比之下),它从来没有任何冲突,并且做了更多的计算。而我的实现非常简单,并且依赖于拥有大量所有可能索引的数组。
我做错了什么?
【问题讨论】:
-
你的机器有多少内存?据我所知,您的阵列使用大约 4GB。
-
请使用内置的基准测试工具。您的时间安排并不代表正在发生的事情,它也会使分析变得更加容易。
-
是的,使用测试基准功能会显示一些更有用的数据,请参阅我的新答案;)
-
@Jaochin Isaksson,我在这台机器上有 128GB 的 RAM。