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

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

内容简介:一句话总结: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设计(中文版)

深入浅出Web设计(中文版)

(美)瓦特罗尔、(美)西罗托 / O'Reilly Taiwan公司 / 东南大学出版社 / 2010-11 / 99.00元

你将从《深入浅出Web设计(中文版)》学到什么?你曾经希望看看书就能学到真正的网站设计吗?曾经想过该如何同时达成让网站看起来美观,又能有效率地沟通信息,还要通过可访问性与可用性的策略吗?《深入浅出Web设计》正是精通上述主题的秘笈。我们将学到如何设计一个绝佳、用户友好的网站,上谈客户需求,下说手绘分镜表,乃至完成在线所需的HTML与css主文件……而且会有一个真正可以运作的网站!一起来看看 《深入浅出Web设计(中文版)》 这本书的介绍吧!

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

Markdown 在线编辑器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具