我想移植一个最先进的哈希函数MeiYan,从C到Go。 (据我所知这是最好的之一,如果不是哈希表在速度和冲突率方面最好的散列函数,它至少击败MurMur。)移植美颜哈希函数Go
我是新来的Go,刚刚花了一个周末与它,并提出了这个版本:
func meiyan(key *byte, count int) uint32 {
type P *uint32;
var h uint32 = 0x811c9dc5;
for ;count >= 8; {
a := ((*(*uint32)(unsafe.Pointer(key))) << 5)
b := ((*(*uint32)(unsafe.Pointer(key))) >> 27)
c := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(key)) + 4))
h = (h^((a | b)^c)) * 0xad3e7
count -= 8
key = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(key)) + 8))
}
if (count & 4) != 0 {
h = (h^uint32(*(*uint16)(unsafe.Pointer(key)))) * 0xad3e7
key = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(key)) + 2))
h = (h^uint32(*(*uint16)(unsafe.Pointer(key)))) * 0xad3e7
key = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(key)) + 2))
}
if (count & 2) != 0 {
h = (h^uint32(*(*uint16)(unsafe.Pointer(key)))) * 0xad3e7
key = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(key)) + 2))
}
if (count & 1) != 0 {
h = (h^uint32(*key));
h = h * 0xad3e7
}
return h^(h >> 16);
}
看起来很凌乱,但我不认为我可以让它看起来更好。现在我测量速度,速度令人沮丧,比使用gccgo -O3
进行编译时比C/C++慢3倍。这可以做得更快吗?这是否与编译器能够做到的一样好或者unsafe.Pointer
转换速度如此慢?实际上,这令我感到惊讶,因为我已经看到一些其他数字处理风格的代码与C一样快,甚至更快。我在这里做一些有益的事情吗?
这里是原来的C代码,我从移植:
u32 meiyan(const char *key, int count) {
typedef u32* P;
u32 h = 0x811c9dc5;
while (count >= 8) {
h = (h^((((*(P)key) << 5) | ((*(P)key) >> 27))^*(P)(key + 4))) * 0xad3e7;
count -= 8;
key += 8;
}
#define tmp h = (h^*(u16*)key) * 0xad3e7; key += 2;
if (count & 4) { tmp tmp }
if (count & 2) { tmp }
if (count & 1) { h = (h^*key) * 0xad3e7; }
#undef tmp
return h^(h >> 16);
}
这是我如何测量速度:
func main(){
T := time.Now().UnixNano()/1e6
buf := []byte("Hello World!")
var controlSum uint64 = 0
for x := 123; x < 1e8; x++ {
controlSum += uint64(meiyan(&buf[0], 12))
}
fmt.Println(time.Now().UnixNano()/1e6 - T, "ms")
fmt.Println("controlSum:", controlSum)
}
为什么不使用Go基准? https://golang.org/pkg/testing/#hdr-Benchmarks –
@GrzegorzŻur简单,因为我到目前为止学习了1.5天。 – exebook
为什么你到处使用不安全? – Flimzy