关于golang随机种子的注意点

go语言里,在并发下,设置随机数种子的方法(Seed())和随机数其他方法(比如,Intn())是不能共存的。

背景:之前在一个项目里需要生成随机数,上线之后总是报有大量的499超时,代码各种优化到没得优化也找不出问题,哪知最后逐行排查打时间戳,居然是随机数的原因,随机数的产生居然需要10来ms。

当时的代码产生随机数是这两句:

rand.Seed(time.Now().UnixNano())
rnd_int := rand.Intn(11)

后来查源码文档有说明:// Seed should not be called concurrently with any other Rand method.

所以以后还是想起他办法去随机数吧,比如给时间戳取模之类的、用shuffle()方法洗牌再取之类。

最后,写了个小程序,可以压测一下看看效果:

package main

import (
        "fmt"
        "math/rand"
        "net/http"
        "strconv"
        "sync"
        "time"
)

type Demo struct {
        rnd  *rand.Rand
        Lock sync.RWMutex
}

func (d Demo) Get() int {
        d.Lock.RLock()
        defer d.Lock.RUnlock()
        d.rnd.Seed(time.Now().UnixNano())
        return d.rnd.Intn(11)
}
func main() {
        // 最快
        http.HandleFunc("/intn", func(w http.ResponseWriter, r *http.Request) {
                t1 := time.Now().UnixNano() / 1e3
                rnd_int := rand.Intn(11)
                t2 := time.Now().UnixNano() / 1e3
                fmt.Println(t2 - t1)
                rnd_str := strconv.Itoa(rnd_int)
                fmt.Fprintln(w, rnd_str, r.URL.Path)
        })
        // 不能并发取,会慢
        http.HandleFunc("/seed", func(w http.ResponseWriter, r *http.Request) {
                t1 := time.Now().UnixNano() / 1e3
                rand.Seed(time.Now().UnixNano())
                rnd_int := rand.Intn(10-0+1) + 0
                t2 := time.Now().UnixNano() / 1e3
                fmt.Println(t2 - t1)
                rnd_str := strconv.Itoa(rnd_int)
                fmt.Fprintln(w, rnd_str, r.URL.Path)
        })
        // 可以并发取,加了锁
        http.HandleFunc("/seedCon", func(w http.ResponseWriter, r *http.Request) {
                t1 := time.Now().UnixNano() / 1e3
                rObj := Demo{
                        rnd : rand.New(rand.NewSource(time.Now().UnixNano())),
                }
                rnd_int := rObj.Get()
                t2 := time.Now().UnixNano() / 1e3
                fmt.Println(t2 - t1)
                rnd_str := strconv.Itoa(rnd_int)
                fmt.Fprintln(w, rnd_str, r.URL.Path)
        })
        //监听3000端口
        http.ListenAndServe(":3000", nil)
}
wrk -t200 -c200 -d60s "http://127.0.0.1:3000/intn"
wrk -t200 -c200 -d60s "http://127.0.0.1:3000/seed"
wrk -t200 -c200 -d60s "http://127.0.0.1:3000/seedCon"

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值