Showing posts with label go language. Show all posts
Showing posts with label go language. Show all posts

20100308

Go Language is lovely

I've been playing with Google's go language for the last week or so, and I have to say its a lovely language. I generally grab the mailing list for anything new I get into, and today someone was looking for a way to wait for a set of go-routines to complete before continuing on in the main thread. Seeing as how common this sort of thing is, I decided to write up a quick library for it.

To use the library first issue a dispatch.New() to acquire a new dispatch mechanism. Then attach any number ( technically upto uint ) of processes to it it via dispatchInstance.Go( func(){ other_process_here() } ). Any number of other processes ( still technically uint ) can wait on the runners to finish before executing.

Anyway, here it is, and hope it's useful for someone.

In dispatch.go :

package dispatch

import "sync"

type Manager interface {
Go( func() )
Wait()
}

type manager struct {
lock sync.Mutex
running uint
waiting uint
wakeup chan bool
}

func New() *manager {
m := new(manager)
m.wakeup = make(chan bool)
return m
}

func (m *manager) Go( fn func() ) {
m.lock.Lock()
m.running++
m.lock.Unlock()

go func(){
fn()

m.lock.Lock()
m.running--
if (m.running == 0) && (m.waiting > 0) {
oc := m.wakeup
nc := make(chan bool)
i := m.waiting
go func(){
for ; i > 0 ; i-- {
oc <- true
}
}()
m.wakeup = nc
m.waiting = 0
}
m.lock.Unlock()
}()
}

func (m *manager) Wait() {
wait := false

m.lock.Lock()
if m.running > 0 {
m.waiting++
wait = true
}
m.lock.Unlock()

if wait {
<- m.wakeup
}
}


And some example usage in main.go :

package main

import "fmt"
import "rand"
import "time"

import "./dispatch"

func main () {
w := dispatch.New()

for i := 0 ; i < 100 ; i++ {
c := i
w.Go( func(){
time.Sleep( rand.Int63n( 1000000000 ) )
fmt.Print( c , "\n" )
w.Go( func(){
time.Sleep( rand.Int63n( 1000000000 ) )
fmt.Print( c , " - second effect\n")
})
})
}

fmt.Print( "All Launched\n" )

w2 := dispatch.New()

for i := 0 ; i < 5 ; i++ {
c := i
w2.Go( func(){
w.Wait()
time.Sleep( rand.Int63n( 1000000000 ) )
fmt.Print("[ " , c , "] This should happen after the first set\n")
})
}

fmt.Print( "Second set all launched\n" )

w.Wait()

for i := 10 ; i < 15 ; i++ {
c := i
w.Go( func(){
time.Sleep( rand.Int63n( 1000000000 ) )
fmt.Print("[ " , c , "] reusing first queue\n")
})
}

fmt.Print( "Main thread past first set\n" )

w2.Wait()

fmt.Print( "Main thread past second set\n" )

w.Wait()

fmt.Print( "Main thread past reuse of first queue\n" )

}


I really like this language. It feels like somebody took many of the best facets of C, javascript and erlang and tucked them into a single package. The static duck-typing is beautiful.

About Me

(2) the subculture of the compulsive programmer, whose ethics prescribe that one silly idea and a month of frantic coding should suffice to make him a life-long millionaire. --ewd1036