面试题答案
一键面试可能遇到的问题
- 性能问题:
math/rand
包中的NewSource
创建的Source
实例不是线程安全的。在并发环境下,多个协程同时调用rand.Intn
等方法,如果共享同一个rand.Rand
实例(由非线程安全的Source
创建),会导致性能问题,因为可能需要频繁加锁。 - 随机数安全性问题:
math/rand
包默认的随机数生成器是伪随机数生成器,如果初始种子相同,生成的随机数序列是相同的,这在需要安全随机数(如加密场景)时是不安全的。
解决方案
- 性能问题解决:为每个协程创建独立的
rand.Rand
实例,每个实例使用不同的Source
。可以使用rand.New
函数,传入rand.NewSource
创建的Source
。 - 安全问题解决:使用
crypto/rand
包来生成安全的随机数。crypto/rand
包使用系统提供的加密安全的随机数生成器。
示例代码
- 使用
math/rand
包解决并发性能问题
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
var numRoutines = 5
var results = make([]int, numRoutines)
var waitGroup sync.WaitGroup
waitGroup.Add(numRoutines)
for i := 0; i < numRoutines; i++ {
go func(index int) {
defer waitGroup.Done()
localRand := rand.New(rand.NewSource(time.Now().UnixNano()))
results[index] = localRand.Intn(100)
}(i)
}
waitGroup.Wait()
fmt.Println(results)
}
- 使用
crypto/rand
包生成安全随机数
package main
import (
"crypto/rand"
"fmt"
"math/big"
)
func main() {
max := big.NewInt(100)
result, err := rand.Int(rand.Reader, max)
if err != nil {
fmt.Println("Error generating random number:", err)
return
}
fmt.Println(result.Int64())
}
在实际应用中,如果需要在并发环境下生成安全随机数,建议优先使用crypto/rand
包。如果对安全性要求不高,只是解决并发性能问题,使用math/rand
包并为每个协程创建独立实例的方法也能满足需求。