package main
import "fmt"
// #1
// This gives the `fatal error: all goroutines are asleep - deadlock!` error, why?
// The `c <- "hello"` is a blocking call, it will wait for another goroutine to read the value
// But this never happens, because there's only the one main goroutine, so the reader `msg := <-c` never gets executed
func main() {
c := make(chan string)
c <- "hello"
msg := <-c
fmt.Println(msg)
}
// #2
// To fix, we can add a _buffer_ to the channel, telling how many messages it can receive
// Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty.
func main() {
// a channel which can receive 2 messages
c := make(chan string, 2)
c <- "hello"
msg := <-c
fmt.Println(msg)
}
// #3
// If we try to send or receive more messages than the buffer allows, we get
// a `fatal error: all goroutines are asleep - deadlock!` again!
func main() {
c := make(chan string, 2)
c <- "hello"
c <- "world"
// send a third message would panic in a deadlock
// c <- "oh noes!"
msg := <-c
fmt.Println(msg)
msg = <-c
fmt.Println(msg)
// receive a third message would panic in a deadlock
// msg = <-c
// fmt.Println(msg)
}
package main
import (
"fmt"
"time"
)
// #1
// It prints `jojo` only once, because the main goroutine continues after the `go send("jojo", c) line`
// The `msg := <- c` is a blocking call, it waits for at least one value and then it continues the execution
// Which prints and exits
func main() {
c := make(chan string)
go send1("jojo", c)
msg := <-c
fmt.Println(msg)
}
func send1(s string, c chan string) {
for i := 0; i < 10; i++ {
c <- s
time.Sleep(1 * time.Second)
}
}
// #2 what if I want to print all the values (until the for loop is finished?)
// We can make an "infinite" for loop on main to block the execution and keep receiving data
// This will work, but will finish with a `fatal error: all goroutines are asleep - deadlock!`
// Because the `send()` function is finished, but `msg` is still waiting for a value which will never be sent
// Go is smart enough to detect this at runtime, and panics with the deadlock error
// How to solve it?
func main() {
c := make(chan string)
go send("jojo", c)
for {
msg := <-c
fmt.Println(msg)
}
}
func send(s string, c chan string) {
for i := 0; i < 3; i++ {
c <- s
time.Sleep(1 * time.Second)
}
}
// #3 One way to solve it is to close the channel when there are no more messages to be sent
// IMPORTANT: ONLY THE SENDER SHOULD CLOSE A CHANNEL, NEVER THE RECEIVER, BECAUSE IT CAN'T KNOW IF THERE ARE MORE VALUES OR NOT!
func main() {
c := make(chan string)
go send("jojo", c)
for {
// a second return value tells us if the channel is still open or not
// so we can take a decision, in this case, to break the loop
msg, open := <-c
if !open {
break
}
fmt.Println(msg)
}
// one can also loop over a channel to achieve the same output as above, just sugar syntax
for msg := range c {
fmt.Println(msg)
}
}
func send(s string, c chan string) {
for i := 0; i < 3; i++ {
c <- s
time.Sleep(1 * time.Second)
}
// closing the channel
close(c)
}
package main
import (
"fmt"
"time"
)
// #1
// The output of this program is one line at time with `1s` and `100ms`, even though
// the first go routine runs way faster. Why?
// Because `fmt.Println()` is a blocking call, it will wait for the value on the second
// goroutine, which will block for one second
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
for {
c1 <- "Every 100ms"
time.Sleep(100 * time.Millisecond)
}
}()
go func() {
for {
c2 <- "Every 1s"
time.Sleep(1000 * time.Millisecond)
}
}()
for {
// Both are blocking calls!
fmt.Println(<-c1)
fmt.Println(<-c2)
}
}
// #2 Fix
func main() {
c1 := make(chan string, 100)
c2 := make(chan string)
go func() {
for {
c1 <- "Every 100ms"
time.Sleep(100 * time.Millisecond)
}
}()
go func() {
for {
c2 <- "Every 1s"
time.Sleep(1000 * time.Millisecond)
}
}()
for {
// This fixes the problem because `select` will keep getting messages from both channels
// in a non blocking fashion
select {
case msg := <-c1:
fmt.Println(msg)
case msg := <-c2:
fmt.Println(msg)
// Sends `hello` to c1
// case c1 <- "hello":
}
}
}