• Home
  • About
  • Sitemap
  • Search
Complete Coding
Subscribe to Complete Coding
Subscribe to Complete Coding

    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

    Related Posts:

    • How To Handle Errors In Google Go
    • How To Use Inheritance In Google Go
    • How To Use Interfaces In Google Go
    • How To Dynamically Allocate Memory In Google Go
    • How To Use Control Structures In Google Go
    Author : kevin | My Website

    {4 comments... read them below or add one}
    1. j says:
      October 20, 2010 at 3:33 pm

      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]

    Leave a Comment
    Click here to cancel reply.

    Click to cancel reply

    « Previous Article Next Article »

    Recent Posts

    • Did We Pass On The Joel Test?
    • Programming Is About Doing The Job Right
    • How should I decide on the programming language to learn next?
    • How To Handle Errors In Google Go
    • How To Achieve Concurrency In Google Go
    Complete Coding Categories
    • development
    • general
    • programming
    • programs
    • today's read
    © 2010-2011 Kevin Rodrigues.