Go: 谨慎使用 math/rand 包中的默认随机数函数

栏目: Go · 发布时间: 6年前

内容简介:一句话总结:math/rand 包中默认的随机数相关函数共享了一个全局锁, 即:所有使用默认随机函数的代码都会去竞争一个全局锁,有时这可能不是你想要的结果。

一句话总结:math/rand 包中默认的随机数相关函数共享了一个全局锁, 即:所有使用默认随机函数的代码都会去竞争一个全局锁,有时这可能不是你想要的结果。

比如 rand.Int63 这个函数的 源代码 如下:

func Int63n(n int64) int64 { return globalRand.Int63n(n) }

可以看到它其实是调用了一个全局的 Rand 实例 globalRand ,我们来看一下 globalRand定义 :

var globalRand = New(&lockedSource{src: NewSource(1).(Source64)})

通过 New 的源码以及 globalRand.Int63n 的源码可以看到关键点是 lockedSource.Int63 方法的定义:

 type lockedSource struct {
     lk  sync.Mutex
     src Source64
 }

 func (r *lockedSource) Int63() (n int64) {
     r.lk.Lock()
     n = r.src.Int63()
     r.lk.Unlock()
     return
 }

通过同样的方法查看其他默认的随机函数可以发现,所有的默认随机函数都共享了一个全局锁,调用这些默认随机函数的时候都会先进行一次获取锁的操作。

大部分情况下不需要管这个全局锁的问题,因为大部分情况下都不会介意这点性能消耗。 如果确实特别在意这点性能消耗的话,可以通过定义一个你的包共享的或者结构体实例共享的 Rand 实例来优化锁的性能消耗(最小化锁的粒度,不跟其他包/代码竞争这个锁)。

例子:

type Xyz struct {
    // Rand 实例不是并发安全的,需要自行解决并发安全问题
    rndMu sync.Mutex
    rnd *rand.Rand
}

func (x *Xyz) random() int32 {
    x.rndMu.Lock()
    n := x.rnd.Int31()
    x.rndMu.Unlock()

    return n
}

func main() {
    x := &Xyz{
        rnd: rand.New(rand.NewSource(time.Now().UnixNano())),
    }
    fmt.Println(x.random())
}

或者可以考虑使用性能更好的第三方 rand 包: valyala/fastrand


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Design for ROI

Web Design for ROI

Lance Loveday、Sandra Niehaus / New Riders Press / 2007-10-27 / USD 39.99

Your web site is a business--design it like one. Billions of dollars in spending decisions are influenced by web sites. So why aren't businesses laser-focused on designing their sites to maximize thei......一起来看看 《Web Design for ROI》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具