Skip to content

Example Using a Channel and Goroutines

Code

package main

func main() {

    /***** Creating a channel and a map *****/

    /* We are creating 2 channels, one for sending and one for receiving.  */
    c, out := make(chan int), make(chan int)

    /* The map  */
    m := map[int]int{1: 2, 3: 4}


    for i, v := range m {
        go func() {
            <-c
            out <- i + v
        }()
    }

    close(c)

    /* Printing to stderr with the builtin `println` function. */
    println(<-out + <-out)
}

Output

14

Explanation

This Go code snippet demonstrates the use of goroutines, channels, and maps to perform concurrent computations and communicate the results via channels.

Line by Line

package main
* This line declares the package name for the current file.
* Every Go file belongs to a package, and package main is special because it defines a package that can be compiled and executed.

func main() {
* This line defines the main function, which is the entry point of a Go program.
* The Go runtime calls this function when the program starts.

c, out := make(chan int), make(chan int)
* This line declares two variables, c and out, each initialized to a new channel of type int.
* The make(chan int) function creates a new channel for transmitting integers.
* Channels are a typed conduit through which you can send and receive values with the channel operator, <-.

m := map[int]int{1: 2, 3: 4}
* Here, a map m is declared and initialized.
* Maps are key-value data structures, and this particular map has both keys and values of type int.
* The map is initialized with two key-value pairs: 1:2 and 3:4.

for i, v := range m {
* This for loop iterates over each entry in the map m.
* The range keyword is used to iterate over elements in a variety of data structures.
* For maps, it returns two values: the key and the value of the current element.
* These are assigned to variables i (the key) and v (the value) for each iteration.

go func() {
* This line starts a goroutine, which is a lightweight thread managed by the Go runtime.
* The go keyword precedes the function call to run the function concurrently.
* The function being called is an anonymous function (a function without a name), defined right there.

<-c
* This line is a blocking receive operation on the channel c.
* The goroutine waits until it can receive a value from c.
* However, since no value is ever sent on c and c is closed before any receive operation, this operation proceeds immediately without retrieving any value due to the channel being closed.

out <- i + v
* This line sends the sum of i and v into the out channel.
* i + v computes the sum of the key and value from the map entry being iterated over in the loop.

}()
* These characters end the anonymous function declaration and immediately invoke it.
* The () at the end calls the function right after defining it.

close(c)
* This line closes the channel c.
* Closing a channel indicates that no more values will be sent on it.
* Receivers can still receive values previously sent on the channel.
* In this context, closing c allows the blocked receive operations in the goroutines to proceed.

println(<-out + <-out)
* This line receives two values from the out channel, adds them together, and prints the result.
* The <-out operation receives a value from out.
* Since there are two goroutines each sending a computed sum to out, this line adds those two sums.
* The order of the values received from out is not deterministic because goroutines run concurrently.


Other Info

  • Concurrency is the composition of independently executing processes, while parallelism (not demonstrated here) is the simultaneous execution of (possibly related) computations.

  • Non-Determinism: The values read from out depend on the order in which goroutines execute, which is non-deterministic.

    • So, the program can produce different outputs on different runs.
  • Channel Closing: Closing a channel is a signal that no more values will be sent on it.
    • Important: Only close a channel from the sender side and to ensure no more sends will happen; otherwise, the program will panic.
  • Deadlock Potential: If not careful, concurrent programs can deadlock.
    • In this case, there's no deadlock because the main goroutine waits for values from out, and each of the spawned goroutines sends a value to out.
    • However, if the logic were changed such that not enough values were sent on out, the program would deadlock waiting on those values.