Go by Example: Goroutines

Here’s a simple example of using goroutines in Go:

package main

import (
	"fmt"
	"time"
)

func printNumbers(c chan int) {
	for i := 0; i < 10; i++ {
		time.Sleep(1 * time.Second)
		c <- i
	}
	close(c)
}

func main() {
	c := make(chan int)
	go printNumbers(c)

	for i := range c {
		fmt.Println(i)
	}
}

In this example, we create a new channel c using make(chan int). Then, we start a new goroutine using the go keyword and call the printNumbers function with c as an argument.

In the printNumbers function, we use a for loop to print numbers from 0 to 9, sleep for one second between each iteration, and send the number to the channel c. After the loop, we close the channel using close(c).

In the main function, we use a for loop to receive numbers from the channel c. The loop will terminate when the channel is closed.

The output of this program will be the numbers 0 to 9, each printed one second apart.

Here’s another example of using goroutines and channels in Go:

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func worker(id int, c chan int) {
	for n := range c {
		time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
		fmt.Printf("Worker %d processed %d\n", id, n)
	}
}

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)
	return c
}

func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		for {
			time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
			out <- i
			i++
		}
	}()
	return out
}

func main() {
	var c1, c2 = generator(), generator()
	var worker = createWorker(0)

	var values []int
	tm := time.After(10 * time.Second)
	tick := time.Tick(time.Second)
	for {
		var activeWorker chan<- int
		var activeValue int
		if len(values) > 0 {
			activeWorker = worker
			activeValue = values[0]
		}
		select {
		case n := <-c1:
			values = append(values, n)
		case n := <-c2:
			values = append(values, n)
		case activeWorker <- activeValue:
			values = values[1:]
		case <-time.After(800 * time.Millisecond):
			fmt.Println("timeout")
		case <-tick:
			fmt.Println("queue length =", len(values))
		case <-tm:
			fmt.Println("bye")
			return
		}
	}
}

In this example, we have two generator functions generator() that generate numbers and send them to a channel. Then, we have a worker function worker() that receives numbers from a channel and processes them. The createWorker function creates a new worker and returns a channel to send values to.

In the main function, we create two generator channels c1 and c2, a worker channel worker, and an empty slice values to store the generated values.

We use a for loop to repeatedly select from multiple channels. The select statement blocks until one of the cases can be executed. We have five cases in the select statement:

  • Receive a number from c1 and append it to values.
  • Receive a number from c2 and append it to values.
  • Send an active value to the active worker and remove it from values.
  • Timeout after 800 milliseconds.
  • Print the length of values every second using a ticker channel tick.
  • Exit the loop after 10 seconds using a

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *