Голанг генерирует идентичные случайные числа в последовательности после времени?(Работает на моей машине) - PullRequest
0 голосов
/ 11 сентября 2018

Я пытаюсь точно понять, почему при вызове из внешней функции мой генератор случайных чисел, отобранный по времени, возвращает последовательности идентичных чисел.

Минимальный рабочий пример выдачи:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

//Generates random int as function of range
func getRand(Range int) int {
    s1 := rand.NewSource(time.Now().UnixNano())
    r1 := rand.New(s1)
    return r1.Intn(Range)
}

//Print 100 random ints between 0 and 100
func main() {
    for i := 0; i < 100; i++ {
        fmt.Print(getRand(100), ", ")
    }
}

Результат этого

Out[1]: 40, 40, 40, 40, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 34,
34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 47, 
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 
47,47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 99, 99, 99, 99, 99, 99, 99, 
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99,

Я хотел бы знать, почему это происходит для моего собственного образования.Я также открыт для предложений для решения.

Подробности: мне нужно вызывать случайные числа во многих внешних функциях моего кода, но, подобно этому MWE, при заполнении внутри функции, отличной от main, они многократно возвращают одни и те же числа.Кроме того, мне нужно динамически обновлять диапазон, поэтому создание списков априори не вариант.Я бы предпочел не генерировать числа в main () и передавать их в каждую функцию - диапазоны вычисляются внутри них, и это усложнит ситуацию

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

Я не эксперт по Go, но я думаю, что проблема - это общая проблема программирования. Это связано с тем, что вы устанавливаете семя для каждого вызова. Семя основано на функции времени. Таким образом, происходит то, что за очень короткое время у вас есть несколько вызовов, в то время как время не изменилось (пока), и поэтому вы получаете одно и то же значение, потому что вы снова и снова устанавливаете одно и то же начальное число.

Попробуйте установить начальное число, только один раз и вне for цикл вызовов.

0 голосов
/ 11 сентября 2018

Это связано с тем, что time.Time имеет гранулярность (равную 1 наносекунде), точно так же, как ваши системные часы (которые могут даже составлять несколько миллисекунд - зависит от многих вещей), и если вы вызываете time.Now() несколько раз в пределах большей из этих гранулярностей, вероятность того, что возвращаемое значение time.Time будет одинаковым, то есть метод Time.UnixNano() вернет вам те же наносекунды (то же число).

И если вы используете то же число, что и начальное число, генератор случайных чисел должен возвращать те же числа.

Вам нужно только заполнить ГСЧ один раз, при запуске приложения, а неперед каждым использованием.Для этого вы можете использовать пакетную init() функцию или в объявлении переменной:

var r = rand.New(rand.NewSource(time.Now().UnixNano()))

//Generates random int as function of range
func getRand(Range int) int {
    return r.Intn(Range)
}

//Print 100 random ints between 0 and 100
func main() {
    for i := 0; i < 100; i++ {
        fmt.Print(getRand(100), ", ")
    }
}

Пример вывода (попробуйте на Go Playground ):

0, 28, 27, 62, 63, 89, 24, 27, 88, 84, 82, 55, 49, 35, 2, 32, 84, 58, 78, 28, 26, 58, 30, 28, 74, 6, 39, 24, 40, 47, 49, 39, 61, 62, 67, 7, 94, 87, 37, 99, 90, 80, 93, 83, 27, 69, 25, 45, 99, 12, 44, 39, 34, 86, 18, 42, 76, 40, 44, 12, 70, 3, 70, 99, 57, 43, 90, 65, 97, 64, 68, 60, 65, 56, 3, 81, 54, 56, 43, 57, 92, 93, 54, 92, 9, 86, 16, 72, 29, 12, 97, 87, 55, 42, 87, 41, 94, 53, 23, 64,

Здесь следует отметить одну вещь: rand.NewSource() возвращает источник, который не безопасен для одновременного использования.Если вам нужно позвонить на номер getRand() из нескольких групп, вам нужно синхронизировать доступ к r или использовать отдельный rand.Rand в каждой программе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...