Skip to content

Instantly share code, notes, and snippets.

@Cijin
Last active April 11, 2022 06:28
Show Gist options
  • Save Cijin/f86e300aa0870668d3040a117f7a9b6e to your computer and use it in GitHub Desktop.
Save Cijin/f86e300aa0870668d3040a117f7a9b6e to your computer and use it in GitHub Desktop.
Unbuffered Channel in Go

Unbuffered Channels

Before I talk about unbuffered channels, let me recap what channels are and how they help make concurrency easier in Go. Channels synchronize go routines as they send and recieve resources they need between each other. When declaring channel we use the make keyword along with the type of data that we are going to share.

Unbuffered and Buffered channels behave differently and understanding both will help you decide which one is more suitable in a given scenario.

Unbuffered channel is channel with no capacity to hold any value before it's recieved.

unbuffered := make(chan int)

With unbuffered channels both go routines have to be ready at the same instant before the send or recieve operation is complete. Synchronization is inherent in the interaction between the send and the receive on the channel.

Once a go routine send data to an unbuffered channel it is locked till the recieving go routine recieves the data.

To understand this better, let's take a look at a program that simulates a relay race b/w 4 go routines

package main

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

var wg sync.WaitGroup

func main() {
	// create an unbuffered channel
	baton := make(chan int)

	// add wait group for the last runner
	wg.Add(1)

	// launch first runner
	go Runner(baton)

	// start the race
	baton <- 1

	// wait for the race to finish
	wg.Wait()
}

func Runner(baton chan int) {
	var newRunner int
	// wait to recieve baton
	runner := <-baton

	// start running
	fmt.Printf("Runner %d running with baton\n", runner)

	// new runner on the line
	if runner != 4 {
		newRunner = runner + 1
		fmt.Printf("Runner %d to the line\n", newRunner)
		go Runner(baton)
	}

	// run
	time.Sleep(100 * time.Millisecond)

	// is the race over?
	if runner == 4 {
		fmt.Printf("Runner %d finished. Race over.\n", runner)
		wg.Done()
		return
	}

	// exchange baton with the next runner
	baton <- newRunner
}

// Runner 1 running with baton
// Runner 2 to the line
// Runner 2 running with baton
// Runner 3 to the line
// Runner 3 running with baton
// Runner 4 to the line
// Runner 4 running with baton
// Runner 4 finished. Race over.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment