关于Golang随机数生成重复数字

最近在尝试用Golang写一个随机图API,但是关于随机数的生成产生了一些问题

原来的代码是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func findImage(s string) []byte {
imageList := make([]string, 0)
//遍历目录
err := filepath.Walk(s,
func(p string, f os.FileInfo, err error) error {
if f == nil {
return nil
}
if f.IsDir() {
return nil
}
ext := path.Ext(f.Name())
if ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif" {
imageList = append(imageList, p)
}
return nil
})
if err != nil {
log.Fatal("in finding img ", err)
}
//返回随机图片
r := rand.New(rand.NewSource(time.Now().Unix()))
i := r.Intn(len(imageList))
img := imageList[i]
b, err := ioutil.ReadFile(img)
if err != nil {
log.Fatal("in opening img ", err)
}
return b
}

我已经注意到需要用系统时间来作为生成随机数的种子,来避免随机序列不变的问题,但是事实上仍然出现了大量的重复数字,反映到程序里就是当快速刷新网页的时候,大概率连续显示的都是同一张图片

采用下列代码再次实验

1
2
3
4
for i := 0; i < 5; i++ {
r := rand.New(rand.NewSource(time.Now().Unix()))
fmt.Println(r.Intn(100))
}

结果打印出来的都是同样的数字

在查阅了资料后发现,由于每次刷新网页该函数都会被调用一次,从而每次都新建了一个rand的对象,但是计算机的处理速度很快,导致时间戳的分辨率不够,一秒内有多个对象被创建,从而它们的种子都是同一个,所以随机序列也是一样的,导致每次从序列取得第一个数字都是一样的

解决方案是将rand对象提升为全局变量,提前声明,这样对象只会被创建一次,大大避免了重复数字的产生

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package randimg

import (
"io/ioutil"
"log"
"math/rand"
"net/http"
"os"
"path"
"path/filepath"
"time"

"github.com/Unknwon/goconfig"
)

var imageDirPath string
var r = rand.New(rand.NewSource(time.Now().Unix()))

//GetRandomImage 返回随机图片
func GetRandomImage(w http.ResponseWriter, r *http.Request) {
w.Write(findImage(imageDirPath))
}

func findImage(s string) []byte {
imageList := make([]string, 0)
//遍历目录
err := filepath.Walk(s,
func(p string, f os.FileInfo, err error) error {
if f == nil {
return nil
}
if f.IsDir() {
return nil
}
ext := path.Ext(f.Name())
if ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif" {
imageList = append(imageList, p)
}
return nil
})
if err != nil {
log.Fatal("in finding img ", err)
}
//返回随机图片
i := r.Intn(len(imageList))
img := imageList[i]
b, err := ioutil.ReadFile(img)
if err != nil {
log.Fatal("in opening img ", err)
}
return b
}

func init() {
cfg, err := goconfig.LoadConfigFile("./config/randimg.ini")
if err != nil {
log.Fatal(err)
}
imageDirPath, err = cfg.GetValue(goconfig.DEFAULT_SECTION, "ImageDirPath")
if err != nil {
log.Fatal(err)
}
}

关于Golang随机数生成重复数字

https://jktu.cc/关于Golang随机数生成重复数字/

作者

udp_bbr

发布于

2019-12-01

更新于

2020-03-25

许可协议