A short program about select statement for channels.
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case s := <-quit:
fmt.Println("quit =",s)
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 9
}()
fibonacci(c, quit)
}
The result of the code above:
0
1
1
2
3
5
8
13
21
34
quit = 9
It worked fine. But after I changed (in func fibonacci)
case s := <-quit:
fmt.Println("quit =",s)
to
case <-quit:
fmt.Println(<-quit)
an fatal error occurred:
0
1
1
2
3
5
8
13
21
34
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.fibonacci(0x18348040, 0x18348080)
/tmp/compile42.go:12 +0xf9
main.main()
/tmp/compile42.go:27 +0x11c
Where does the error come from?
In second case you are getting the value form the channel two times. Every time you do something like <-channel you pop one value out of channel.
Hence program is waiting indefinitely on line
fmt.Println(<-quit)
but fortunately go is intelligent enough to detect this situation and panic with error "all goroutines are asleep - deadlock!"
The line
fmt.Println(<-quit)
is waiting for another value on the channel, which will never come, according to the code you have.
You have to keep in mind the line before in the select:
case s := <-quit
has already removed the quit value from the channel.
Thus it will never complete.
Related
Here is my program.
package main
import "fmt"
func init() {
fmt.Println("init function")
}
func main() {
// gen number to naturals channel
naturals := gen(1, 2, 3)
// write the squars in a channel
squar := dosquar(naturals)
for p := range squar {
fmt.Println("printer shows----- ", p)
}
}
func gen(nums ...int) chan int {
naturals := make(chan int)
go func() {
for _, n := range nums {
fmt.Println("generating number ", n)
naturals <- n
fmt.Println("generated number ", n)
}
//close(naturals)
}()
return naturals
}
func dosquar(naturals chan int) chan int {
// write the squars the values
squar := make(chan int)
go func() {
for number := range naturals {
fmt.Println("recieved number ", number)
squar <- number * number
fmt.Println("sent squar of number ", number*number)
}
//close(squar)
}()
return squar
}
It gives following error.
init function
generating number 1
generated number 1
generating number 2
recieved number 1
sent squar of number 1
recieved number 2
generated number 2
generating number 3
printer shows----- 1
printer shows----- 4
sent squar of number 4
recieved number 3
sent squar of number 9
printer shows----- 9
generated number 3
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/Users/siyaram/go/src/github.com/SrmHitter9062/go-pipeline/main.go:15 +0x127
goroutine 19 [chan receive]:
I expect it to be running as channels are being ranged.That leads me to a question that do we need to close the channel every time, when we are finished with them ?
Please somebody help clarifying why program is not working as expected.
You can do whatever you want, but a range loop over a channel won't exit until the channel is closed.
I just started learning golang, while I was going through concurrency I accidentally wrote this code:
import (
"fmt"
)
func squares(c chan int) {
for i := 0; i < 4; i++ {
num := <- c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main start")
c := make(chan int)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4
go squares(c)
c <- 5
c <- 6
c <- 7
c <- 8
fmt.Println("main stop")
}
Originally I was suppose to assign c := make(chan int, 3).
I am having trouble understanding the output of the code I've written.
main start
1
4
9
25
36
49
16
main stop
I would like to understand how the code is executed.
I was expecting error: all goroutines are asleep - deadlock!
Many thanks!
I am not sure to really understand what you wanted to achieve, especially the reason of that weird loop :
for i := 0; i < 4; i++ {
num := <- c
fmt.Println(num * num)
}
But anyway.
First have all, some explanations on how works channels and goroutines.
A Channel is a thread safe messaging pipe used to share data accross differents executions contexts. A channel is creating with make instruction, then
c := make(chan int, 3)
means create a channel of int type with a "buffer" size of 3. This element is very important to understand. Channel do follow a producer / consumer pattern with that bases rules :
For producer :
if I try to push some data in a channel with some "free space", it doesn't block and next instructions are executed
If I try to push some data in a channel without "free space", it blocks till previous has been treated
For consumer :
If I try to take element from an empty channel, it block untill some data come
If I try to take element from a non empty channel, it take the first (Channel is a FIFO)
Please note that all blocking operations may be turned non-blocking using some special pattern available through select instruction, but that's another subject :).
Goroutine are light sub-processes, routines (No thread). It is no place here to explain all in details, but what is important is 1 goroutine === 1 execution stack.
So in your case, the output is quite predictable till there is only one consumer. Once you start the second Goroutine, the consumption order is still predictable (the size of the channel is only one), but the execution order not !
One thing is noticable: you have only 7 output... That because your main goroutine ends before it happends, terminating the whole program execution. That point explain why you didn't have the all goroutines are asleep - deadlock!.
If you want to have that, you just should add <- c somewhere at the end of the main :
package main
import (
"fmt"
)
func squares(c chan int) {
for i := 0; i < 4; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main start")
c := make(chan int)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4
go squares(c)
c <- 5
c <- 6
c <- 7
c <- 8
<-c
fmt.Println("main stop")
}
You will have the behavior I think you expect :
main start
1
4
9
25
36
49
64
16
fatal error: all goroutines are asleep - deadlock!
Edit : on step by step, execution :
// a goroutine is created and c is empty. because
// the code of `squares` act as a consumer, the goroutine
// "block" at instruction `num := <-c`, but not the main goroutine
go squares(c)
// 1 is pushed to the channel. Till "c" is not full the main goroutine
// doesn't block but the other goroutine may be "released"
c <- 1
// if goroutine of squares has not consume 1 yet, main goroutine block
// untill so, but is released just after
c <- 2
// it continues with same logic
c <- 3
c <- 4
// till main goroutine encountered `<- c` (instruction I added) .
// Here, it behave as a consumer of "c". At this point all
// goroutine are waiting as consuler on "c" => deadlock
I'm new to the Go language and am currently going through the Go tour. I have a question regarding the concurrency example 5 on the select statement.
The code below has been edited with print statements to trace statements execution.
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
fmt.Printf("Run fib with c: %v, quit: %v\n", c, quit)
for {
select {
case c <- x:
fmt.Println("Run case: c<-x")
x, y = y, x+y
fmt.Printf("x: %v, y: %v\n", x, y)
case <-quit:
fmt.Println("Run case: quit")
fmt.Println("quit")
return
}
}
}
func runForLoop(c, quit chan int) {
fmt.Println("Run runForLoop()")
for i := 0; i < 10; i++ {
fmt.Printf("For loop with i: %v\n", i)
fmt.Printf("Returned from c: %v\n", <-c)
}
quit <- 0
}
func main() {
c := make(chan int)
quit := make(chan int)
go runForLoop(c, quit)
fibonacci(c, quit)
}
The following is printed to the console.
Run fib with c: 0xc00005e060, quit: 0xc00005e0c0
Run runForLoop()
For loop with i: 0
Returned from c: 0 // question 1
For loop with i: 1
Run case: c<-x // question 2
x: 1, y: 1
Run case: c<-x // question 2
x: 1, y: 2
Returned from c: 1
For loop with i: 2
Returned from c: 1
For loop with i: 3
// ...
My questions are
The value of c is received here is 0 even though none of the select blocks have been executed. Could I confirm that this is the zero value of the c variable that has int type?
Why is case c<-x executed twice?
For 1: It prints the result of <-c, which will block until another goroutine writes to it. So your statement is not correct: the select case for c<-x ran, with x=0. It is not the zero value of the chan variable. You will only read the zero-value of the chan type from a channel if the channel is closed, or if you use the two-value form of channel read: value,ok := <-c. When ok=false, value is the zero-value of the channel value type.
For 2: c<-x will execute 10 times, because you read from it 10 times in the for-loop, and only then you are writing to quit, which will enable the second case of the select. What you observe here is the second iteration of the loop.
I'm new with golang channels and could not underestimate why does program behavior changes if I specify channel buffer size
package main
import (
"fmt"
)
func channels(in <-chan bool, out chan int) {
for {
select {
case _ = <-in:
fmt.Println("Close")
close(out)
return
default:
fmt.Println("Out")
out <- 1
break
}
}
}
func main() {
in := make(chan bool)
// in := make(chan bool, 1)
out := make(chan int)
go channels(in, out)
i := 0
// Loop:
for n := range out {
fmt.Println(n)
i += 1
if i > 10 {
fmt.Println("Send close")
in <- true // Here it is became asleep
return
}
}
fmt.Println("Done")
}
Output is:
Out
Out
1
1
Out
Out
1
1
Out
Out
1
1
Out
Out
1
1
Out
Out
1
1
Out
Out
1
Send close
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/home/user/go-lessons/3/chan_4.go:39 +0x2c3
goroutine 19 [chan send]:
main.channels(0xc820072060, 0xc8200720c0)
/home/user/go-lessons/3/chan_4.go:16 +0x241
created by main.main
/home/user/go-lessons/3/chan_4.go:27 +0x97
exit status 2
If I replace in := make(chan bool) with in := make(chan bool, 1) It works properly. Why does it happen?
This is because the main goroutine is stuck writing to in
in <- true
and the other goroutine is stuck writing to out
out <- 1
If you make the write to out a case aswell it should work:
for {
select {
case <-in:
fmt.Println("Close")
close(out)
return
case out <- 1:
fmt.Println("Out")
break
}
}
I'm facing an annoying problem. When I try to use wg.Add() to sync my routines, a deadlock error is raised.
package main
import (
"fmt"
"sync"
)
func hello(ch chan int, num int, wg *sync.WaitGroup) {
for {
i := <-ch
if i == num {
fmt.Println("Hello number:", i)
ch <- (num - 1)
defer wg.Done() // Same happens without defer
return
}
ch <- i
}
}
func main() {
fmt.Println("Start")
var wg sync.WaitGroup
ch := make(chan int)
for i := 0; i < 10; i++ {
wg.Add(1)
go hello(ch, i, &wg)
}
ch <- 9
wg.Wait()
fmt.Println("End")
}
Outputs:
Start
Hello number: 9
Hello number: 8
Hello number: 7
Hello number: 6
Hello number: 5
Hello number: 4
Hello number: 3
Hello number: 2
Hello number: 1
Hello number: 0
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc04203a20c)
C:/Go/src/runtime/sema.go:47 +0x3b
sync.(*WaitGroup).Wait(0xc04203a200)
C:/Go/src/sync/waitgroup.go:131 +0x81
main.main()
C:/Users/Augusto Dias/Documents/GoLang/MT.go:34 +0x1a0
goroutine 18 [chan send]:
main.hello(0xc0420380c0, 0x0, 0xc04203a200)
C:/Users/Augusto Dias/Documents/GoLang/MT.go:13 +0x197
created by main.main
C:/Users/Augusto Dias/Documents/GoLang/MT.go:29 +0x151
exit status 2
When I use wg.Add(9) outside the for block, I got no error.
func main() {
fmt.Println("Start")
var wg sync.WaitGroup
ch := make(chan int)
wg.Add(9) // Use wg.Add(10) will raise deadlock too
for i := 0; i < 10; i++ {
go hello(ch, i, &wg)
}
ch <- 9
wg.Wait()
fmt.Println("End")
}
Outputs:
Start
Hello number: 9
Hello number: 8
Hello number: 7
Hello number: 6
Hello number: 5
Hello number: 4
Hello number: 3
Hello number: 2
Hello number: 1
End
Why is this happening, I mean, why routines goes asleep when I wait for them all? Use the same channel for send and receive can be the source of this problem?
Channel 0 (the call go hello(ch, 0, &wg)) since it is the last channel alive gets stuck on this line
ch <- (num - 1)
It is attempting to send to a channel but no one is there to receive it. Thus the function will wait indefinitely and never be done.
Some suggestions for how to remove this problem
create a consumer in the main loop
make the channel ch non blocking