rand.* in Go can be faster
It first started when I was trying to benchmark one of my systems, I built a small utility in go to benchmark it’s perfromance however something was weird, the benchmarking tool that was way simpler than the system was actually slower.
So naturally the next night was spent diving into why.
The code of the benchmark tool was a little something like this:
On my test machine I was getting around 17.4M calls / second but only half of my CPU was in use :\
Running pprof yeilded an interesting result, it seemed that the application was mostly wating on a mutexLock for the Rand function
The reason for that is when using rand pkg without specifeing the source of the random it usess a global one that is locked behind a mutex.
So our bottleneck is actually the acquiring of the mutex to getnerate a random number.
Lets fix it, in each goroutine lets create it’s own rand generator:
With this the performance jumped to 65.3M call /second a x3.5 improvment! and CPU utilization is now 100%
Conclusion:
- When using rand heavily in a system make sure to use multiple instances of long lived rand struct per go routine
- Don’t overdo it, if you have many goroutines going up and down consider using sharding for your rand provider like so.
- Profile you application using `go tool pprof -http=: http://localhost:6060/debug/pprof/profile?seconds=10` to discover any bottlenecks