Cómo sembrar correctamente el generador de números aleatorios en Go: secretos de rendimiento

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

La aleatoriedad es demasiado seria como para dejarla al azar

\n\n

Cualquiera que haya escrito código en Go al menos una vez se ha enfrentado a la generación de números aleatorios. El generador de números aleatorios (RNG) es algo engañoso. En apariencia es simple: llamas a rand.Intn() y obtienes un número. Pero si no prestas atención al sembrado correcto (seed), tu "aleatoriedad" se convertirá en una secuencia predecible que romperá las pruebas, fallará en criptografía o simplemente te sorprenderá con resultados idénticos en cada ejecución.

\n\n

En Stack Overflow, la pregunta "How to properly seed random number generator" ha acumulado miles de visitas. La gente se confunde con time.Now().UnixNano(), usa crypto/rand donde no es necesario y sufre de bajo rendimiento. Hoy analizaremos este tema con Go como ejemplo, sin rodeos, con benchmarks reales y soluciones listas para usar.

\n\n

¿Por qué el seed no es solo una formalidad?

\n\n

Seed (semilla) es el estado inicial del generador. La misma semilla produce la misma secuencia de números. Esto es útil para depuración, pero mortal para producción si esperas impredecibilidad.

\n\n

En Go, el paquete estándar math/rand utiliza un algoritmo determinista. Si olvidas llamar a rand.Seed(), entonces... Hasta Go 1.20, el generador por defecto usaba una semilla fija (generalmente 1). A partir de Go 1.20, math/rand se siembra automáticamente con un valor aleatorio al iniciar el programa. Sin embargo, confiar en esto en lugares críticos es una mala práctica.

\n\n

El principal problema de los principiantes es intentar sembrar el generador para cada número aleatorio:

\n\n
// ❌ MAL: recreamos el generador cada vez\nfunc getRandom() int {\n    r := rand.New(rand.NewSource(time.Now().UnixNano()))\n    return r.Intn(100)\n}
\n\n

¿Por qué es malo? time.Now().UnixNano() da nanosegundos, pero en realidad la precisión depende del SO. En Windows, por ejemplo, puede ser de ~15 ms. Si llamas a la función dos veces seguidas, obtendrás números idénticos. Además, cada llamada a rand.NewSource crea un nuevo objeto, sobrecargando el recolector de basura.

\n\n

Top 3 enfoques para sembrar en Go

\n\n

1. Método clásico: seed global una sola vez

\n\n

La opción más simple y correcta para la mayoría de las aplicaciones es establecer el seed una vez al iniciar el programa.

\n\n
package main\n\nimport (\n    "fmt"\n    "math/rand"\n    "time"\n)\n\nfunc main() {\n    // ✅ BIEN: sembramos una sola vez\n    rand.Seed(time.Now().UnixNano())\n\n    for i := 0; i < 5; i++ {\n        fmt.Println(rand.Intn(100))\n    }\n}
\n\n

Importante: time.Now().UnixNano() da un valor único, pero si el programa se ejecuta varias veces en el mismo nanosegundo (poco probable, pero teóricamente posible), el seed será el mismo. Para el 99% de las aplicaciones, esto es suficiente.

\n\n

2. Generador local para aislamiento

\n\n

Cuando tienes varias gorutinas o no quieres afectar el estado global, crea tu propia instancia de rand.Rand.

\n\n
func NewSeededGenerator() *rand.Rand {\n    seed := time.Now().UnixNano()\n    return rand.New(rand.NewSource(seed))\n}\n\n// Uso:\nrng := NewSeededGenerator()\nfor i := 0; i < 3; i++ {\n    fmt.Println(rng.Intn(100))\n}
\n\n

Este enfoque brinda control total: diferentes gorutinas pueden tener sus propios generadores y no se bloquean entre sí (el rand global usa un mutex).

\n\n

3. Seed criptográfico para tareas críticas

\n\n

Si necesitas aleatoriedad real (tokens, contraseñas, criptografía), olvídate de math/rand. Usa crypto/rand:

\n\n
import (\n    "crypto/rand"\n    "encoding/binary"\n    "math/rand"\n)\n\nfunc CryptoSeed() int64 {\n    var buf [8]byte\n    _, err := rand.Read(buf[:])\n    if err != nil {\n                

Blogs

Book Recommendations