title: Generating random numbers concurrently in Go
body: <p>I'm new to Go and to concurrent/parallel programming in general. In order to try out (and hopefully see the performance benefits of) goroutines, I've put together a small test program that simply generates 100 million random <code>int</code>s - first in a single goroutine, and then in as many goroutines as reported by <code>runtime.NumCPU()</code>.</p>
  
  <p>However, I consistently get worse performance using more goroutines than using a single one. I assume I'm missing something vital in either my programs design or the way in which I use goroutines/channels/other Go features. Any feedback is much appreciated.</p>
  
  <p>I attach the code below.</p>
  
  <pre><code>package main
  
  import "fmt"
  import "time"
  import "math/rand"
  import "runtime"
  
  func main() {
    // Figure out how many CPUs are available and tell Go to use all of them
    numThreads := runtime.NumCPU()
    runtime.GOMAXPROCS(numThreads)
  
    // Number of random ints to generate
    var numIntsToGenerate = 100000000
    // Number of ints to be generated by each spawned goroutine thread
    var numIntsPerThread = numIntsToGenerate / numThreads
    // Channel for communicating from goroutines back to main function
    ch := make(chan int, numIntsToGenerate)
  
    // Slices to keep resulting ints
    singleThreadIntSlice := make([]int, numIntsToGenerate, numIntsToGenerate)
    multiThreadIntSlice := make([]int, numIntsToGenerate, numIntsToGenerate)
  
    fmt.Printf("Initiating single-threaded random number generation.\n")
    startSingleRun := time.Now()
    // Generate all of the ints from a single goroutine, retrieve the expected
    // number of ints from the channel and put in target slice
    go makeRandomNumbers(numIntsToGenerate, ch)
    for i := 0; i &lt; numIntsToGenerate; i++ {
      singleThreadIntSlice = append(singleThreadIntSlice,(&lt;-ch))
    }
    elapsedSingleRun := time.Since(startSingleRun)
    fmt.Printf("Single-threaded run took %s\n", elapsedSingleRun)
  
  
    fmt.Printf("Initiating multi-threaded random number generation.\n")
    startMultiRun := time.Now()
    // Run the designated number of goroutines, each of which generates its
    // expected share of the total random ints, retrieve the expected number
    // of ints from the channel and put in target slice
    for i := 0; i &lt; numThreads; i++ {
      go makeRandomNumbers(numIntsPerThread, ch)
    }
    for i := 0; i &lt; numIntsToGenerate; i++ {
      multiThreadIntSlice = append(multiThreadIntSlice,(&lt;-ch))
    }
    elapsedMultiRun := time.Since(startMultiRun)
    fmt.Printf("Multi-threaded run took %s\n", elapsedMultiRun)
  }
  
  
  func makeRandomNumbers(numInts int, ch chan int) {
    source := rand.NewSource(time.Now().UnixNano())
    generator := rand.New(source)
    for i := 0; i &lt; numInts; i++ {
          ch &lt;- generator.Intn(numInts*100)
      }
  }
  </code></pre>