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
* 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() {
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)
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}
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 {
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() {
* 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
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
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.
}()
* The
()
at the end calls the function right after defining it.
close(c)
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)
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 toout
. - However, if the logic were changed such that not enough values were sent on
out
, the program would deadlock waiting on those values.
- In this case, there's no deadlock because the main goroutine waits for values from