golangのrandパッケージのlockについて
rand.Intとか叩くと、実は中でlockかかってますよねっていう話です。
randパッケージってgoroutine safeなの?
math/randを使ってるサンプルではrand.Intとか直接叩いてて、Rand構造体を自分で作ってないじゃないですか?
そこで気になったわけです、これってgoroutine safeなのかどうか
CLIコマンドとか作ってて、goroutineの中で叩かないのであれば別に気にする必要ないんだけど、httpのハンドラの場合、それは自ずとgoroutineで起動するので(少なくともnet/httpはね)goroutine safeかどうか気にする必要があるんだよね。
ほんで、ググってて以下のブログエントリを見つけた。
The Hidden Dangers of Default Rand · Scott Mansfield
ロードジェネレータを作ってて、goroutineの中でmath/randを叩いてたら、あまりにもパフォーマンスが出ないので、math/randのソースを見たらlockしているのを発見した。というような内容 (詳しくは記事を読んで)
よって、中でlockかけてるからmath/randはgoroutine safeなんだね。
lockかかってるっつーことは、複数のgoroutineから叩くワークロードの場合、パフォーマンスが出ないのでは?
上記のブログエントリのロードジェネレータの場合がまさにそれで、ロック解除待ちが問題になっている。
httpハンドラの場合もgoroutineなので、ロック時間が問題になるのでは〜と思ったんだけど、普通のwebアプリの場合そこがホットスポットになることは稀なのか。 (だから日本語の記事は特にヒットしなかったのかな?)
一応回避策としては単純で、goroutineごとにRand構造体を作って、それを叩けという話になるようだ。
r := rand.New(rand.NewSource(time.Now().Unix()))
てな具合に。(UnixNanoのほうがいいかな)
普通のwebアプリの場合、早すぎる最適化になるのかもしれないけど、どっちみちユニットテストのためにInterfaceでラッパー被せといたほうがいいんだよな。math/rand直接叩くより