Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Faster alternative to math/rand that is not synchronized

Tags:

go

I'm trying to optimise my genetic algorithm. This uses a lot of random number selection (random mutations, etc).

I decided to use the CPU profiler:

import (
    "runtime/pprof"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func main() {

    if *cpuprofile != "" {
        fmt.Println(*cpuprofile)
        f, err := os.Create(*cpuprofile)
        if err != nil {
            log.Fatal(err)
        }
        _ = pprof.StartCPUProfile(f)
        defer pprof.StopCPUProfile()
    }
    ***app logic***

I was surprised to see that one of the top contributors to the CPU usage was sync.(*Mutex).Unlock, notably because I have not used threads or goroutines at any point in my application.

pprof result

Some digging revealed the bottleneck is caused by the default source in math/rand being synchronized.

Is there a faster way for me to generate random numbers with functions that are not synchronized/blocking?

True randomness/accurate pseudo-randomness is not so important for this application, but it'd be preferred if I didn't get the exact same numbers multiple times in close succession.

like image 359
OscarVanL Avatar asked Oct 21 '25 14:10

OscarVanL


1 Answers

As you found, the default "randomness source" for the math/rand package is a locked source, suitable for use in concurrent goroutines. You will need to create one new source per goroutine using the NewSource function, and then one random number generator from that, using New. The pseudo-random numbers from this new generator will work the same way as the (single) locked source except that each generator will produce its own stream of identically-generated numbers if started from the same seed.

You'll therefore want to ensure that each seed you provide to NewSource is unique, so that each stream is different.

like image 171
torek Avatar answered Oct 23 '25 06:10

torek