Skip to content

Instantly share code, notes, and snippets.

@nathanwdavis
Last active December 21, 2015 10:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nathanwdavis/6290428 to your computer and use it in GitHub Desktop.
Save nathanwdavis/6290428 to your computer and use it in GitHub Desktop.
Messing around with really CPU intensive math ops and comparing simple for loops vs. goroutine per loop vs. partitioning into multiple goroutines (lightweight, green threads) in Go. The range partitioned goroutine-based solution tends to run around 3.5 - 4x faster than the simple for loop using 8 goroutines. The one that uses a goroutine per loo…
/*
Example Output:
➜ go run partitioned_loops.go
Starting...
simpleFor result: 468767562500, time: 0.013604745000000001 sec
goForEach result: 468767562500, time: 24.106190332 sec
goPartitioned result: 468767562500, time: 0.004296383 sec
*/
package main
import (
"fmt"
"io/ioutil"
"runtime"
"time"
)
const iterations = 1e6 //must be even number for now
const maxThreads = 10
func main() {
primeGoThreads(maxThreads)
fmt.Print("Starting...\n")
timeIt(simpleFor, "simpleFor")
timeIt(goForEach, "goForEach") //this dies and takes the machine with it if iterations is much more than 1e6
//timeIt(simpleForInGo, "simpleForInGo") //no diff from simpleFor
timeIt(goPartitioned, "goPartitioned")
}
type action func() int64
func timeIt(f action, title string) {
start := time.Now()
result := f()
fmt.Printf("%s \t result: %v, time: %v sec \n",
title, result, time.Since(start).Seconds())
}
func inner(in int64, iteration int) int64 {
ret := (in + int64(iteration)*(1/2)) / 4
shape := [4]int64{int64(iteration + 1), ret, in, in * 2}
ret = ((shape[1]*2)-(shape[0]+shape[3]))/8 + 1
return ret - (int64(iteration) / 4)
}
func deriveInput(iteration int) int64 {
return iterations - int64(iteration) + 100
}
func simpleFor() int64 {
var ret int64
for i := 0; i < iterations; i++ {
ret -= inner(deriveInput(i), iterations)
}
return ret
}
func goForEach() int64 {
var ret int64
ch := make(chan int64, 1000)
fn := func(i int, ch chan int64) {
ch <- inner(deriveInput(i), iterations)
}
for i := 0; i < iterations; i++ {
go fn(i, ch)
}
for i := 0; i < iterations; i++ {
ret -= <-ch
}
return ret
}
func simpleForInGo() int64 {
var ret int64
ch := make(chan int64)
fn := func(ch chan int64) {
ch <- simpleFor()
}
go fn(ch)
ret = <-ch
return ret
}
func goPartitioned() int64 {
var ret int64
const parts = 8 //should be a power of 2 (2,4,8,16, etc)
const partSize = iterations / parts
ch := make(chan int64)
fn := func(start, till int, ch chan int64) {
ch <- simpleForRange(start, till)
}
for i := 0; i < parts; i++ {
go fn(i*partSize, (i+1)*partSize, ch)
}
for i := 0; i < parts; i++ {
ret += <-ch
}
return ret
}
func simpleForRange(start, till int) int64 {
var ret int64
for i := start; i < till; i++ {
ret -= inner(deriveInput(i), iterations)
}
return ret
}
func primeGoThreads(maxThreads int) {
runtime.GOMAXPROCS(maxThreads)
fn := func(i int) {
a := i / 2
fmt.Fprint(ioutil.Discard, a)
}
for i := 1; i < maxThreads*100; i++ {
go fn(i)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment