I have some code where i am trying to print the content of a channel in a goroutine using fmt.Println. Here is the simplified version of code.
package main
import "fmt"
import "time"
func main() {
ch := make(chan int)
go fmt.Println(<-ch);
ch<- 10;
time.Sleep(time.Second * 10);
}
When I run the above code I am getting this error.
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
C:/cygwin64/home/vmadhusudana/go/channel.go:9 +0x67
exit status 2
However it works fine when I call fmt.Println from a function
package main
import "fmt"
import "time"
func main() {
ch := make(chan int)
go func(){fmt.Println(<-ch)}();
ch<- 10;
time.Sleep(time.Second * 10);
}
What is making the difference here?
In the first version, the channel read is performed from the main go-routine - hence the deadlock.
The second version, the read is done from the created go-routine.
Basically this:
go fmt.Println(<-ch);
becomes:
v := <-ch
go fmt.Println(v);
As the parameters to the function are evaluated before it's invocation.
P.S. The defer statement behaves similarly. So always use a closure if you want the value passed to a go-routine or defer statement to be evaluated at "runtime".
// receive the value from channel firstly
// then create new goroutine to println
go fmt.Println(<-ch)
// receive channel in new goroutine
go func(){fmt.Println(<-ch)}()
https://play.golang.org/p/xMyqd-Yr8_a
this will help you to understand the order of exec.
Related
I read it on (https://www.geeksforgeeks.org/channel-in-golang/) that:
"In the channel, the send and receive operation block until another side is not ready by default.
It allows goroutine to synchronize with each other without explicit locks or condition variables."
To test above statement, I have written a sample program mentioned below:
Program:
package main
import (
"fmt"
"sync"
"time"
)
func myFunc(ch chan int) {
fmt.Println("Inside goroutine:: myFunc()")
fmt.Println(10 + <-ch) //<-- According to rule, control will be blocked here until 'ch' sends some data so that it will be received in our myFunc() go routine.
}
func main() {
fmt.Println("Start Main method")
// Creating a channel
ch := make(chan int)
go myFunc(ch) //<-- This go routine started in a new thread
time.Sleep(2 * time.Second) //<--- introduced a Sleep of 2 seconds to ensure that myFunc() go routine executes before main thread
ch <- 10
fmt.Println("End Main method")
}
I was expecting below output:
Start Main method
Inside goroutine:: myFunc()
20
End Main method
But, Actual output received is:
Start Main method
Inside goroutine:: myFunc()
End Main method
Why the value sent through channel is not printed?
I think, it is because main thread finished its execution first and hence, all other goroutine also terminated.
If that is the case, then, why does the rule said - It allows goroutine to synchronize with each other without explicit locks or condition variables.
Because, to get the expected output, I have to use sync.WaitGroup to tell the main thread to wait for the other goroutine to finish. Isn't it violating the above rule as I am using locks in form of waitgroup?
PS: I am learning golang. So please forgive if I get the concept totally wrong.
The main goroutine exists before the myFunc goroutine is able to print the output. Here is an implementation which ensures that myFunc goroutine finishes before the main goroutine exits.
package main
import (
"fmt"
"sync"
"time"
)
func myFunc(ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("Inside goroutine:: myFunc()")
fmt.Println(10 + <-ch) //<-- According to rule, control will be blocked here until 'ch' sends some data so that it will be received in our myFunc() go routine.
}
func main() {
fmt.Println("Start Main method")
// Creating a channel
ch := make(chan int)
wg := sync.WaitGroup{}
wg.Add(1)
go myFunc(ch, &wg) //<-- This go routine started in a new thread
time.Sleep(2 * time.Second) //<--- introduced a Sleep of 2 seconds to ensure that myFunc() go routine executes before main thread
ch <- 10
wg.Wait()
fmt.Println("End Main method")
}
The channels are used here for synchronization and it works as described in documentation. It does not mean that the code starting from this point in the code will be executed at the same speed. It only means that main goroutine will not continue if myFunc goroutine is not reading from channel. And myFunc will wait for main goroutine to push data to channel. After this happen both goroutines will continue it execution independently.
Try this, used your code as basis
package main
import (
"fmt"
"time"
)
func myFunc(ch chan int, done chan struct{}) {
defer close(done) // channel will be closed in the function exit phase
fmt.Println("Inside goroutine:: myFunc()")
fmt.Println(10 + <-ch) //<-- According to rule, control will be blocked here until 'ch' sends some data so that it will be received in our myFunc() go routine.
}
func main() {
fmt.Println("Start Main method")
// Creating a channel
ch := make(chan int)
done := make(chan struct{}) // signal channel
go myFunc(ch, done) //<-- This go routine started in a new thread
time.Sleep(2 * time.Second) //<--- introduced a Sleep of 2 seconds to ensure that myFunc() go routine executes before main thread
ch <- 10
<-done // waiting for function complete
fmt.Println("End Main method")
}
Or use Jaroslaw's suggestion.
Because go is so fast... https://play.golang.org/p/LNyDAA3mGYY
After you send to channel scheduler isn't fast enoght... and program exists. I have introduced an additional context switcher for scheduler to show effect.
Yes, you are right
I think, it is because main thread finished its execution first and hence, all other goroutine also terminated.
If you check the above program execution. The sleep is before main thread writes to the channel. Now even though which goroutine() will have CPU time is completely arbitary, but in the above case if the main sleeps before the explicit sleep logic. myFunc will be blocked as there is no data in ch
Here I made a slight change to the above code to make main sleep after writing data into Channel. It gives the expected output, Without using waitgroup or quit channels.
package main
import (
"fmt"
"time"
)
func myFunc(ch chan int) {
fmt.Println("Inside goroutine:: myFunc()")
fmt.Println(10 + <-ch) //<-- According to rule, control will be blocked here until 'ch' sends some data so that it will be received in our myFunc() go routine.
}
func main() {
fmt.Println("Start Main method")
// Creating a channel
ch := make(chan int)
go myFunc(ch) //<-- This go routine started in a new thread
ch <- 10
time.Sleep(2 * time.Second) //<--- introduced a Sleep of 2 seconds to ensure that myFunc() go routine executes before main thread
fmt.Println("End Main method")
}
It is currently a race condition between the myFunc being able to print and your main function exiting.
If we look at the spec for program execution at
https://golang.org/ref/spec#Program_execution
Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.
It is still your job to make sure that all spawned goroutines will complete before your main goroutine exists.
In your case, you could use a waitgroup as you mentioned or you could use a done channel.
https://play.golang.org/p/RVr0HXuUMgn
Given your code you could also close the channel you use to send the integer over since you are passing it to the function as bidirectional but it's not strictly idiomatic.
https://play.golang.org/p/wGvexC5ZgIi
I have 2 channels which I pass values to at the start of main function and then I have an anonymous goroutine which should print the values:
package main
import (
"fmt"
)
func main() {
rand1 := make(chan int)
rand2 := make(chan int)
rand1 <- 5
rand2 <- 7
go func() {
select {
case <-rand1:
fmt.Println("rand1")
case <-rand2:
fmt.Println("rand2")
return
}
fmt.Println("test")
}()
}
However I receive the error fatal error: all goroutines are asleep - deadlock!. But the anonymous goroutine is supposed to return when rand2 channel is receives its value.
The write to a channel will block until another goroutine reads from it. Your program is trying to write to a channel before you start the reader goroutine. Start the reader goroutine first, and then write to the channels.
Not that the way it is written, the goroutine will only read from one of the channels and return, so your program will deadlock again because the second write will block.
main.go
func main() {
fmt.Println("hello")
ch := make(chan struct{}, 1)
<-ch
}
main_test.go
func Test_Main(t *testing.T) {
main()
}
go run main.go
hello
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
but
go test -v main_test.go -run=Test_Main
=== RUN Test_Main
hello
go test will not report an error and will always run.
After consulting a lot of information, I didn't find an answer to explain this phenomenon. Maybe my way is wrong?This channel method is used in projects.
Thanks.
When you run a regular program, it waits for input from channel. And because there is only one goroutine there is no way to receive the input from channel (no other thread to send to it). Thus deadlock is reported.
On the other hand test runner uses goroutines to execute tests. So there is more then one goroutine spawned and the deadlock is not detected (runtime assumes that other goroutine could send to channel).
To answer your question from comment: go run and go test are not supposed to achieve the same effects. go run executes your program, go test executes procedures that test your code. These commands executes two different programs.
I am not sure if you can detect this kind of errors (deadlocks) with tests.
Edit:
go test waits for test to finish (you can configure how long with -timeout d option). So I assume it spawns goroutine that waits for timer.Timer to expire, so there is no deadlock (there is always one goroutine that has a chance to be executed).
Edit2:
Try this program:
package main
import (
"fmt"
"time"
)
func main() {
go func() {
t := time.NewTimer(10 * time.Second)
<-t.C
}()
fmt.Println("hello")
ch := make(chan struct{}, 1)
<-ch
}
It waits 10 seconds before reporting deadlock.
Edit3:
Or take a look at flowing code that illustrates how test runner works:
package main
import (
"fmt"
"time"
)
func original_main_func() {
fmt.Println("hello")
ch := make(chan struct{}, 1)
<-ch
}
func test() {
original_main_func()
}
func test_runner() {
ch := make(chan struct{}, 1)
go func() {
test()
close(ch)
}()
t := time.NewTimer(10 * time.Second)
select {
case <-t.C:
panic("timeout")
case <-ch:
fmt.Println("test executed")
}
}
func main() {
test_runner()
}
I am trying to understand the difference between calling goroutine with/without anonymous function.
When I try below code with anonymous function it works.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
fmt.Println(<-ch)
}()
go send(1, ch)
time.Sleep(100 * time.Millisecond)
}
Below code without a anonymous function fails with deadlock.
go fmt.Println(<-ch) //fatal error: all goroutines are asleep - deadlock!
The code is available here
The Go Programming Language Specification
Receive operator
For an operand ch of channel type, the value of the receive operation
<-ch is the value received from the channel ch. The channel direction
must permit receive operations, and the type of the receive operation
is the element type of the channel. The expression blocks until a
value is available.
For example,
package main
import "fmt"
func main() {
ch := make(chan int)
go fmt.Println(<-ch)
ch <- 1
}
Playground: https://play.golang.org/p/K3_V92NRWvY
Output:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
// At prog.go: line 7: (<-ch)
fmt.Println(<-ch) evaluates its arguments, a receive on ch. There is no send pending for ch. fmt.Println(<-ch) blocks until a value is available, which never happens, it never gets to ch <- 1.
It is equivalent to:
package main
import "fmt"
func main() {
ch := make(chan int)
arg := <-ch
go fmt.Println(arg)
ch <- 1
}
Playground: https://play.golang.org/p/1wyVTe-8tyB
Output:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
// At prog.go: line 7: arg := <-ch
I am trying to understand goroutines.
In the following example, why do 1)--4) behave differently?
See https://play.golang.org/p/_XXZe47W53v
package main
import (
"fmt"
"time"
)
func send(x int, ch chan int) {ch<-x}
func read(ch chan int) {fmt.Println(<-ch)}
func main() {
ch := make(chan int)
go read(ch) // 1) works
go send(1,ch) // -> 1
// go fmt.Println(<-ch) // 2) fatal error: all goroutines are asleep - deadlock!
// go send(1,ch) // isn't this the same as the above ?
// go send(1,ch) // 3) works
// go fmt.Println(<-ch) // -> 1
// go fmt.Println(<-ch) // 4) fatal error: all goroutines are asleep - deadlock!
// go send(1,ch) // why does the order of the go routine calls matter?
time.Sleep(100*time.Millisecond)
}
You are seeing the errors because the read is not happening inside of the goroutine, but in the main thread.
The line:
go fmt.Println(<-ch)
is evaluating the parameter in the main thread, and once it succeeds it will run the Println in the goroutine with the already resolved parameter. Since the code can never write to the ch in this state, it deadlocks.
You can observe this by changing it to:
go func() { fmt.Println(<-ch) }()
Then it will create a closure around the ch, and then the anonymous routine will be blocked, not the main thread, which can continue on to the send().