Seed 和 Rand.Seed 的区别

use*_*659 3 random go

golang 文档说

与 Rand.Seed 方法不同,Seed 可以安全地并发使用。

rand.Seed从实际上是math/rand包,但什么是种子?如果Seed是另一个函数,那么它不存在,math/rand所以不清楚该函数来自哪里?

更新: 我正在探索main我们执行的演示程序

rand.Seed(time.Now().UnixNano())
go process(...)
go process(...)    
Run Code Online (Sandbox Code Playgroud)

其中process确定像

func process(...) {
    time.Sleep(time.Duration(rand.Intn(30)) * time.Second)
    ...
}
Run Code Online (Sandbox Code Playgroud)

我们在两个不同的线程中使用相同的种子,那么这样的使用是否rand.Seed被认为是线程不安全的?

icz*_*cza 5

有一个功能,就有一个方法。您的报价来自于rand.Seed() Rand.Seed() Rand.Seed()方法。

math/rand包的全局函数在全局rand.Rand实例上运行。如果您检查以下源代码rand.Seed()

func Seed(seed int64) { globalRand.Seed(seed) }
Run Code Online (Sandbox Code Playgroud)

全局函数对于并发使用是安全的,因此所有其他包都可以使用它(以共享方式)。全球rand.Rand提供实例是为了方便起见,您可以“开箱即用”使用它,无需任何准备(除非需要对其进行正确播种)且无需任何同步。

的实例rand.Rand并发使用是不安全的,每个需要rand.Rand确定性随机序列的goroutine都应该创建一个,并适当地播种。或者如果 arand.Rand要在多个 goroutine 之间共享,则需要显式同步。

使用全局的优点 rand.Rand(通过全局函数)的是:(1)易于使用(与所有人隐式共享)和(2)不需要同步。

创建和使用自定义rand.Rand实例的优点:(1)它更快(它不是隐式同步)和(2)你可以控制谁可以访问它,所以你可以用它来重复伪随机序列(你可以不要对全局实例执行此操作,因为“任何人”都可以与您同时使用它)。

编辑:

我们在两个不同的线程中使用相同的种子,那么这样的使用是否rand.Seed被认为是线程不安全的?

你只调用rand.Seed一次,所以实际上它是否线程安全都没有关系,它不是并发调用的。如果rand.Seed()同时从多个 goroutine 中调用,那么并发使用是否安全才重要。正如我在前面的回答中所述:“全局函数对于并发使用是安全的......”

您同时从多个 goroutine 调用的是rand.Intn(),但同样,这样做是安全的。