Golang中为什么rand.seed不起作用?
Golang中为什么rand.seed不起作用? 我认为以下代码应该总是生成相同的结果,因为在init函数中有rand.Seed来确保rand.Intn生成相同的随机整数序列。但实际上每次运行都会得到不同的结果。我是否误解了rand.Seed函数?
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var (
wg sync.WaitGroup
)
func init(){
rand.Seed(time.Now().UnixNano())
}
func main(){
wg.Add(2)
court := make(chan int)
go play("James", court)
go play("Yun", court)
court <- 1
wg.Wait()
}
func play(name string, court chan int){
defer wg.Done()
for {
ball, ok := <- court
if !ok {
fmt.Printf("player %s won\n", name)
return
}
n := rand.Intn(100)
if n % 13 == 0{
fmt.Printf("Player %s missed\n", name)
close(court)
return
}
fmt.Printf("Player %s Hit %d\n", name, ball)
court <- ball + 1
}
}
谢谢
更多关于Golang中为什么rand.seed不起作用?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢 @NobbZ 提供的详细解释!
更多关于Golang中为什么rand.seed不起作用?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
一旦你设法在相同的纳秒时间内设置种子,它就会生成相同的序列。但由于这种情况极不可能发生,所以每次的种子都是不同的。
抱歉,RNG是什么意思?我对此还很陌生,不太清楚。你的意思是使用纳秒级时间作为半随机数吗?但实际上每次运行都会生成不同的结果,所以在我看来这完全是随机的,而不是半随机的。
很好,谢谢。
想知道作者为什么要这样做?我的意思是,如果作者想通过 rand.Seed 获得相同的结果,为什么他要使用总是生成不同结果的纳秒时间?这对我来说很奇怪……为什么不直接使用 rand.Seed(1) 呢?
rand.Seed(1)
RNG 是随机数生成器。
当前时间戳的随机性因素在这里并不是关键,我们真正需要的是打破原有的可预测序列。
设想这样一个场景:
几年前有人编写了一个能够运行"小行星"街机版本的机器人程序,经过约2秒的游戏观察后,它就能计算出用于初始化RNG的种子值。从那一刻起,它甚至能够预判尚未生成的小行星动向。
定期使用新种子重新初始化RNG可以打破这种可预测性,使得预判未来状态变得更为困难。
但问题在于,如果继续使用旧序列中的新数值,观察者仍有可能推测出后续数值并延续之前的预测模式。而如果采用当前时间戳,由于观察者的系统时钟可能存在数纳秒的偏差,就无法确定精确数值——即便是单纳秒的差异也会产生完全不同的序列。
不过在某些场景下,可重现性反而是必要的。以多语言测试运行器为例,它们通常会打乱测试执行顺序。这类工具通常会输出所使用的种子值,并支持通过参数指定种子来复现之前的执行顺序(前提是测试用例数量未发生变动)。
另一个典型案例是程序化关卡生成器,例如在Roguelike类游戏中。开发者无需保存实际的关卡布局数据,只需存储种子值,在需要时即可重新生成对应关卡。
func main() {
fmt.Println("hello world")
}
在您的代码中,rand.Seed 确实被调用了,但问题在于您使用了 time.Now().UnixNano() 作为种子值。由于 time.Now().UnixNano() 返回当前时间的纳秒级时间戳,每次运行程序时这个值都不同,导致随机数序列不重复。如果您希望每次运行生成相同的随机数序列,需要使用固定的种子值,例如一个常量整数。
以下是修改后的代码示例,使用固定种子值(如 42)来确保可重复的随机数序列:
package main
import (
"fmt"
"math/rand"
"sync"
)
var (
wg sync.WaitGroup
)
func init() {
rand.Seed(42) // 使用固定种子值
}
func main() {
wg.Add(2)
court := make(chan int)
go play("James", court)
go play("Yun", court)
court <- 1
wg.Wait()
}
func play(name string, court chan int) {
defer wg.Done()
for {
ball, ok := <-court
if !ok {
fmt.Printf("player %s won\n", name)
return
}
n := rand.Intn(100)
if n%13 == 0 {
fmt.Printf("Player %s missed\n", name)
close(court)
return
}
fmt.Printf("Player %s Hit %d\n", name, ball)
court <- ball + 1
}
}
在这个版本中,每次运行程序都会生成相同的输出,因为种子是固定的。如果您需要基于时间的随机性(例如在游戏或模拟中),保留 time.Now().UnixNano() 是正确的;否则,使用固定种子用于测试或可重复场景。


