DevDevデブ!!

プログラミングのこととか書きます。多分。。。

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直接叩くより