我写了这个函数来为我的测试用例生成随机唯一id:
func uuid(t *testing.T) string {
uidCounterLock.Lock()
defer uidCounterLock.Unlock()
uidCounter++
//return "[" + t.Name() + "|" + strconv.FormatInt(uidCounter, 10) + "]"
return "[" + t.Name() + "|" + string(uidCounter) + "]"
}
var uidCounter int64 = 1
var uidCounterLock sync.Mutex
为了测试它,我在不同的goroutine中从它生成一堆值,将它们发送到主线程,通过执行map[string]int
将结果放入map[v] = map[v] + 1
。没有对此地图的并发访问权限,它对主线程是私有的。
var seen = make(map[string]int)
for v := range ch {
seen[v] = seen[v] + 1
if count := seen[v]; count > 1 {
fmt.Printf("Generated the same uuid %d times: %#v\n", count, v)
}
}
当我将uidCounter
转换为字符串时,我在一个键上发生了大量的碰撞。当我使用strconv.FormatInt
时,我根本没有碰撞。
当我说一吨时,我的意思是我刚从1115919
生成的值中获得值[TestUuidIsUnique|�]
的{{1}}次碰撞,即50%的值在同一个键上发生碰撞。价值观不相等。对于相同的源代码,我总是得到相同数量的冲突,所以至少它有点确定性,即可能与竞争条件无关。
我并不感到惊讶2227980
中的整数溢出会成为一个问题,但我还远不及2 ^ 31,这也不能解释为什么地图认为50%的值具有相同的键。此外,我不希望哈希冲突影响正确性,只影响性能,因为我可以遍历地图中的键,因此值存储在某处。
在输出中,打印的所有符文均为rune
。它与最高有效的unicode代码点的位数相同,但也不是真正匹配。
0xEFBFBD
这里发生了什么?那些作者是否认为Generated the same uuid 2 times: "[TestUuidIsUnique|�]"
Generated the same uuid 3 times: "[TestUuidIsUnique|�]"
Generated the same uuid 4 times: "[TestUuidIsUnique|�]"
Generated the same uuid 5 times: "[TestUuidIsUnique|�]"
...
Generated the same uuid 2047 times: "[TestUuidIsUnique|�]"
Generated the same uuid 2048 times: "[TestUuidIsUnique|�]"
Generated the same uuid 2049 times: "[TestUuidIsUnique|�]"
...
暗示hash(a) == hash(b)
表示字符串?或者我只是错过了一些愚蠢的事情? a == b
也没有抱怨。
我在macOS go test -race
和10.13.2
。
答案 0 :(得分:7)
无效符文的字符串转换返回包含unicode替换字符的字符串:“ ”。
使用strconv包将整数转换为文本。