How To Achieve Concurrency In Google Go
| 17th October 2010 |
Concurrency can be achieved in Google Go by using goroutines. A goroutine is a function executing in parallel with other goroutines in the same address space.
Advantages of goroutines:
1) Lightweight, costing little more than allocation of stack space.
2) Simpler than thread management.
Prefix a function or method call with the go keyword to run the call in a new goroutine.
go list.Sort() // run list.Sort in parallel; don't wait for it.
A function literal can be handy in a goroutine invocation.
func Announce(message string, delay int64) {
go func() {
time.Sleep(delay)
fmt.Println(message)
}() // Note the parentheses - must call the function.
}
Channels
Channels are used to communicate between goroutines.
Like maps, channels are a reference type and are allocated with make. If an optional integer parameter is provided, it sets the buffer size for the channel. The default is zero, for an unbuffered or synchronous channel.
ci := make(chan int) // unbuffered channel of integers cj := make(chan int, 0) // unbuffered channel of integers cs := make(chan *os.File, 100) // buffered channel of pointers to Files
Any value may be sent over a channel. To send a value on a channel, use <- as a binary operator. To receive a value on a channel, use <- as a unary operator. When calling functions, channels are passed by reference.
package main
import "fmt"
func thread(ch chan int){
fmt.Println("Thread")
ch <- 1 //send the signal on the channel
}
func main(){
ch := make(chan int)
go thread(ch) //starts a goroutine
<-ch //blocks till goroutine sends the signal
fmt.Println("Main")
}
Receivers always block until there is data to receive.
Mutex
We can use channels to achieve the functionality of mutex as below. Thanks to MizardX for the example.
package main
var global int = 0
var c = make(chan int, 1)
func thread1(){
<-c // Grab the ticket
global = 1
c <- 1 // Give it back when were done
}
func thread2(){
<-c // Grab the ticket
global = 2
c <- 1 // Give it back when were done
}
func main() {
c <- 1 // Put the initial value into the channel
go thread1()
go thread2()
}
Alternatively, mutex are available in Google Go in the sync package. It contains the Lock() and Unlock() functions to use mutex as shown below.
package main
import "sync"
var global int = 0
var m sync.Mutex
func thread1(){
m.Lock()
global = 1
m.Unlock()
}
func thread2(){
m.Lock()
global = 2
m.Unlock()
}
func main(){
go thread1()
go thread2()
}
A more idiomatic way to use a sync.Mutex would be in an struct as shown below. (Thanks to j for providing a better program).
package main
import "sync"
type Global struct {
Value int
sync.Mutex
}
var g Global
func thread1(){
g.Lock()
g.Value = 1
g.Unlock()}
func thread2(){
g.Lock()
g.Value = 2
g.Unlock()
}
func main(){
go thread1()
go thread2()
}
Useful links:
Effective Go
Go for C++ Programmers
The Go Memory Model



A more idiomatic way to use a sync.Mutex would be in an struct:
type Global struct {
Value int
sync.Mutex
}
var g Global
Then, you can use it as:
g.Lock()
g.Value = 1
g.Unlock()
and you don’t need to track which lock corresponds to each value
[Reply]
kevin Reply:
October 20th, 2010 at 9:22 pm
Thanks for a better way of using mutex with lock, j.
[Reply]