Rabarar's Blog

A blogging framework for mild hackers.

Golang Scribbles

| Comments

So I was bored an thought I’d write some go code to demonstrate a few interesting features in Go!

Take a look at

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package main

import (
        "fmt"
        "sync"
        "time"
)

const (
        MAXFUNCS = 100
)

func main() {

        var x struct {
                sync.Mutex
                y func(int) int
                z int
        }

        var xx = make(chan struct {
                sync.Mutex
                y func(int) int
                z int
        })

        for i := 0; i < MAXFUNCS; i++ {
                go func(num int) {
                        x.Lock()
                        x.y = z
                        x.z = x.y(42 * num)
                        fmt.Printf("x.z = %d\n", x.z)
                        xx <- x
                        x.Unlock()
                }(i)
        }

        to := 0
        gets := 0

        for {
                select {
                case num := <-xx:
                        to = 0
                        fmt.Printf("got %d\n", num.z)
                        gets++
                default:
                        fmt.Printf("sleeping...\n")
                        time.Sleep(1 * time.Second)
                        to++
                }

                if to > 5 {
                        break
                }
        }

        fmt.Printf("received %d gets before timeout\n", gets)

}

func z(w int) int {
        return w / 2
}

Here I want to highlight a few cool concepts in Go:

  • Anonymous structures
  • Bi-directional Channels
  • Go Routines
  • Non-blocking Channels
  • Anonymous fields in structures
  • Closures

This toy program defines a variable x that is an anonymous struct that has an anonymous field that is a sync.Mutux. Why make this field anonymous? Well, by doing so, we can Lock() and Unlock() the structure without needlessly specifying a fieldname. Simply x.Lock() will lock the Mutux.

Next we create a channel of type that’s equivalent to the unnamed stucture type. We do this by mirroring the definition of the unnamed structure in the variable definition.

Now that we’ve defined our variables, we create a bunch of go routines using a function closure. We define a function that takes an int as our closure. We then Lock() our variable, assign a function to memeber x.y and call the function passing in the integer and returning the result to x.z. Now that we’ve assigned values to x we pass it down the channel xx. Lastly we Unlock() the Mutux.

At this point we’ve fired up a bunch of go routines, and sent copies of our anonymous struct down the channel.

Next we start and infinite loop (yikes!) and check our channel for results in our main go-routine.

The first case in the select checks to see if we’ve received a message on the channel. If we have we print out the value that we assigned to our integer field in our anonymous structure and tally the reeipt of a message on the channel.

If we don’t receive a message, we default to our default case where we manage a timeout counter, to, After 5 consecutive seconds of not receiving any messages, we break our infinite loop, and report a timeout and display how many messages we received prior to timing out.

What might make this example more interesting is to delay each go routine by a random amount of time and see if our reception of messages completes prior to receiving all of the messages.

Try modifying the function z as follows and see what happens

1
2
3
4
func z(w int) int {
        time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
        return w/2
}

This more realistically demonstrates how the Non-blocking channel works when reading mesages at an unpredictable rate.

Comments