diff --git a/rand/randomizer.go b/rand/randomizer.go new file mode 100644 index 0000000..04af3bf --- /dev/null +++ b/rand/randomizer.go @@ -0,0 +1,99 @@ +package rand + +import ( + cryptoRand "crypto/rand" + "encoding/binary" + "golang.org/x/exp/rand" + "hash/maphash" + mathRand "math/rand" + "runtime" + "time" +) + +type SeedType string + +const ( + UnixNanoSeed SeedType = "UnixNano" + MapHashSeed SeedType = "MapHash" + CryptoRandSeed SeedType = "CryptoRand" + RandomStringSeed SeedType = "RandomString" +) + +type Randomizer struct { + seedType SeedType +} + +func NewRandomizer(seedType SeedType) *Randomizer { + return &Randomizer{ + seedType: seedType, + } +} + +func (r *Randomizer) UnixNano() int64 { + // 获取当前时间戳 + timestamp := time.Now().UnixNano() + + // 生成一个随机数 + var randomBytes [8]byte + _, err := rand.Read(randomBytes[:]) + if err != nil { + panic("failed to generate random bytes") + } + randomPart := int64(binary.LittleEndian.Uint64(randomBytes[:])) + + // 获取 Goroutine ID(或其他唯一标识) + goroutineID := int64(runtime.NumGoroutine()) + + // 结合时间戳、随机数和 Goroutine ID + seed := timestamp ^ randomPart ^ goroutineID + + return seed +} + +func (r *Randomizer) MapHash() int64 { + return int64(new(maphash.Hash).Sum64()) +} + +func (r *Randomizer) CryptoRand() int64 { + var b [8]byte + _, err := cryptoRand.Read(b[:]) + if err != nil { + panic("cannot seed math/rand package with cryptographically secure random number generator") + } + seed := int64(binary.LittleEndian.Uint64(b[:])) + return seed +} + +var Alpha = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789" + +func (r *Randomizer) RandomString() int64 { + const size = 8 + buf := make([]byte, size) + for i := 0; i < size; i++ { + buf[i] = Alpha[mathRand.Intn(len(Alpha))] + } + seed := int64(binary.LittleEndian.Uint64(buf[:])) + + return seed +} + +func (r *Randomizer) Seed() int64 { + switch r.seedType { + default: + fallthrough + case UnixNanoSeed: + return r.UnixNano() + case MapHashSeed: + return r.MapHash() + case CryptoRandSeed: + return r.CryptoRand() + case RandomStringSeed: + return r.RandomString() + } +} + +// Seed generates a seed based on the specified SeedType. +func Seed(seedType SeedType) int64 { + randomizer := NewRandomizer(seedType) + return randomizer.Seed() +} diff --git a/rand/randomizer_test.go b/rand/randomizer_test.go new file mode 100644 index 0000000..73f3923 --- /dev/null +++ b/rand/randomizer_test.go @@ -0,0 +1,80 @@ +package rand + +import ( + "fmt" + "testing" +) + +func TestUnixNano(t *testing.T) { + randomizer := NewRandomizer(UnixNanoSeed) + + var seeds = make(map[int64]bool) + for i := 0; i < 100000; i++ { + seed := randomizer.Seed() + seeds[seed] = true + } + fmt.Println("UnixNano Seed", len(seeds)) +} + +func TestMapHash(t *testing.T) { + randomizer := NewRandomizer(MapHashSeed) + + var seeds = make(map[int64]bool) + for i := 0; i < 100000; i++ { + seed := randomizer.Seed() + seeds[seed] = true + } + fmt.Println("MapHash Seed", len(seeds)) +} + +func TestCryptoRand(t *testing.T) { + randomizer := NewRandomizer(CryptoRandSeed) + + var seeds = make(map[int64]bool) + for i := 0; i < 100000; i++ { + seed := randomizer.Seed() + seeds[seed] = true + } + fmt.Println("CryptoRand Seed", len(seeds)) +} + +func TestRandomString(t *testing.T) { + randomizer := NewRandomizer(RandomStringSeed) + + var seeds = make(map[int64]bool) + for i := 0; i < 100000; i++ { + seed := randomizer.Seed() + seeds[seed] = true + } + fmt.Println("RandomString Seed", len(seeds)) +} + +func TestSeed(t *testing.T) { + var seeds = make(map[int64]bool) + for i := 0; i < 100000; i++ { + seed := Seed(UnixNanoSeed) + seeds[seed] = true + } + fmt.Println("UnixNano Seed", len(seeds)) + + seeds = make(map[int64]bool) + for i := 0; i < 100000; i++ { + seed := Seed(MapHashSeed) + seeds[seed] = true + } + fmt.Println("MapHash Seed", len(seeds)) + + seeds = make(map[int64]bool) + for i := 0; i < 100000; i++ { + seed := Seed(CryptoRandSeed) + seeds[seed] = true + } + fmt.Println("CryptoRand Seed", len(seeds)) + + seeds = make(map[int64]bool) + for i := 0; i < 100000; i++ { + seed := Seed(RandomStringSeed) + seeds[seed] = true + } + fmt.Println("RandomString Seed", len(seeds)) +}