The following code runs perfectly fine:
package main
import (
"fmt"
)
func my_func(c chan int){
fmt.Println(<-c)
}
func main(){
c := make(chan int)
go my_func(c)
c<-3
}
playgound_1
However if I change
c<-3
to
time.Sleep(time.Second)
c<-3
playground_2
My code does not execute.
My gut feeling is that somehow main returns before the my_func finishes executing, but it seems like adding a pause should not have any effect. I am totally lost on this simple example, what's going on here?
When the main function ends, the program ends with it. It does not wait for other goroutines to finish.
Quoting from the Go Language Specification: 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.
So simply when your main function succeeds by sending the value on the channel, the program might terminate immediately, before the other goroutine has the chance to print the received value to the console.
If you want to make sure the value gets printed to the console, you have to synchronize it with the event of exiting from the main function:
Example with a "done" channel (try it on Go Playground):
func my_func(c, done chan int) {
fmt.Println(<-c)
done <- 1
}
func main() {
c := make(chan int)
done := make(chan int)
go my_func(c, done)
time.Sleep(time.Second)
c <- 3
<-done
}
Since done is also an unbuffered channel, receiving from it at the end of the main function must wait the sending of a value on the done channel, which happens after the value sent on channel c has been received and printed to the console.
Explanation for the seemingly non-deterministic runs:
Goroutines may or may not be executed parallel at the same time. Synchronization ensures that certain events happen before other events. That is the only guarantee you get, and the only thing you should rely on.
2 examples of this Happens Before:
The go statement that starts a new goroutine happens before the goroutine's execution begins.
A send on a channel happens before the corresponding receive from that channel completes.
For more details read The Go Memory Model.
Back to your example:
A receive from an unbuffered channel happens before the send on that channel completes.
So the only guarantee you get is that the goroutine that runs my_func() will receive the value from channel c sent from main(). But once the value is received, the main function may continue but since there is no more statements after the send, it simply ends - along with the program. Whether the non-main goroutine will have time or chance to print it with fmt.Println() is not defined.
Related
Why is there a deadlock in the following code? I am trying to return something from the goroutine to outside
package main
import (
"fmt"
"syscall/js"
"time"
)
func test(this js.Value, i []js.Value) interface{} {
done := make(chan string, 1)
go func() {
doRequest := func(this js.Value, i []js.Value) interface{} {
time.Sleep(time.Second)
return 0
}
js.Global().Set("doRequest", js.FuncOf(doRequest))
args := []js.Value{js.ValueOf("url")}
var x js.Value
doRequest(x, args)
done <- "true"
}()
aa := <-done
fmt.Println(aa)
return 0
}
func main() {
c := make(chan bool)
js.Global().Set("test", js.FuncOf(test))
<-c
}
When I run this on a browser and call test(), the following error will be shown
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
.....
Pretty much what it says in the error message. All goroutines are asleep. main doesn't start anything and just does a channel receive, so it's blocked, and no other goroutines are running, so there's no possibility that main could ever wake up again, so the runtime panics.
If I recall correctly, unlike regular Go, GopherJS doesn't shut everything down and exit if main exits (in part because: what exactly would that even mean? The closest analog to a Go program would be to close the webpage! Which would kind of suck. So GopherJS doesn't do that.). So what you're doing to keep main alive is not necessary, strictly speaking, in GopherJS.
That said, if you say (for example) time.Sleep(time.Hour) at the end instead, then while all goroutines are still asleep (strictly speaking), main will eventually wake up, which the runtime knows, so it doesn't panic in that case.
As to your actual test function, once you do try it, you get a related error message: Uncaught Error: runtime error: cannot block in JavaScript callback, fix by wrapping code in goroutine. test does a blocking call on a channel, and GopherJS won't allow that in a function called directly from Javascript, so it panics. (When I run it in the playground, I also get Uncaught TypeError: r is not a function, but that's just fallout from the earlier error.)
I think what you're trying to do is wait for doRequest to finish, print the value, and return, but that won't work. You'll need to use a native Javascript promise, or some other asynchronous mechanism, for that.
func main() {
c := make(chan bool)
js.Global().Set("test", js.FuncOf(test))
<-c
}
You have made a channel c, and then wait to receive a value from it. Notice how c is a variable local to the main function. The reference to c is never passed anywhere else in the program, so there can never be a value sent on the c channel, and thus your main goroutine will wait forever to receive.
I am trying to understand channels in Go. I have read that by default sends and receives block until both the sender and receiver are ready. But how do we figure out readyness of sender and receiver.
For example in the following code
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
The program will get stuck on the channel send operation waiting forever for someone to read the value. Even though we have a receive operation in println statement it ends up in a deadlock.
But for the following program
package main
import "fmt"
func main() {
ch := make(chan int)
go func () {
ch <- 1
}()
fmt.Println(<-ch)
}
The integer is passed successfully from go routine to main program. What made this program work? Why second works but first do not? Is go routine causing some difference?
Let's step through the first program:
// My notes here
ch := make(chan int) // make a new int channel
ch <- 1 // block until we can send to that channel
// keep blocking
// keep blocking
// still waiting for a receiver
// no reason to stop blocking yet...
// this line is never reached, because it blocks above forever.
fmt.Println(<-ch)
The second program splits the send off into its own line of execution, so now we have:
ch := make(chan int) // make a new int channel
go func () { // start a new line of execution
ch <- 1 // block this second execution thread until we can send to that channel
}()
fmt.Println(<-ch) // block the main line of execution until we can read from that channel
Since those two lines of execution can work independently, the main line can get down to fmt.Println and try and receive from the channel. The second thread will wait to send until it has.
The go routine absolutely makes a difference. The go routine that writes to the channel will be blocked until your main function is ready to read from the channel in the print statement. Having two concurrent threads, one that reads and one that writes fulfills the readiness on both sides.
In your first example, the single thread gets blocked by the channel write statement and will never reach the channel read.
You need to have a concurrent go routine to read from a channel whenever you write to it. Concurrency goes hand-in-hand with channel usage.
I am learning channels in Go by following this tutorial.
When I only send value to a channel it gives error. Here is the example code.
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println("Does not work")
}
Here I am just sending value to the channel but not receiving anything. It give an error
fatal error: all goroutines are asleep - deadlock!
But when I run following code it doesn't give any error
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
fmt.Println("did not receive but still works")
}
and prints
did not receive but still works
I couldn't understand why it works in second case while it does not work in first case. Even though I have not received any value for the channel in both cases. Also what is causing the deadlock in first case and how it gets avoided in second case?
Neither example works. In fact, no example that only sends to a channel will ever work, in any traditional sense of "work".
But here's a step through of each, to make it clear:
First example
ch := make(chan int)
This creates an unbuffered channel. Unbuffered channels don't hold any data, they only act as a conduit for communication--all data sent must be received by something else, before the program execution proceeds--on either side of the channel.
ch <- 1
Here you send data on the channel, but nothing is waiting to receive it, so the program waits. In this case, it waits forever, because you never created a receiver for the channel, thus your deadlock.
Second example
c := make(chan int)
Again, create an unbuffered channel.
go sum(s[:len(s)/2], c)
Call the sum function, which, incidentally, will also block forever, for the reasons described above--nothing is receiving on the channel, so it will wait forever. However, in this case, you've called it in a goroutine. The goroutine will run in a separate execution thread, while other bits of the program run. Although, due to never receiving data from the channel, this goroutine will never exit, until the main program exits.
go sum(s[len(s)/2:], c)
Again, you call sum, and again, in a goroutine. So at this point, you have three gorotuines: One running main(), and one each running an invocation of sum(). The latter two will never exit.
Then your program exits. When the program exits, all goroutines (including the two that are stuck forever waiting on your channel) exit.
Since this program exits immediately, the deadlock is never reported, but it does assuredly exist, same as in your first example.
Here is a simple example code about unbuffered channels:
ch01 := make(chan string)
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
fmt.Println("We are in the main goroutine")
ch01 <- "Hello"
The result I got:
We are in the main goroutine
We are in the sub goroutine
Hello
Go playground:
https://play.golang.org/p/rFWQbwXRzGw
From my understanding, the send operation blocked the main goroutine, until the sub goroutine executed a receive operation on channel ch01. Then the program exited.
After placing the sub goroutine after the send operation like that:
fmt.Println("We are in the main goroutine")
ch01 <- "Hello"
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
A deadlock occurred:
We are in the main goroutine
fatal error: all goroutines are asleep - deadlock!
go playground
https://play.golang.org/p/DmRUiBG4UmZ
What happened this time? Did that mean after ch01 <- "Hello" the main goroutine was immediately blocked so that the sub goroutine had no chance to run? If it is true, how should I understand the result of the first code example?(At first in main goroutine, then in sub goroutine).
An unbuffered channel blocks on send until a receiver is ready to read. In your first example a reader is set up first, so when the send occurs it can be sent immediately.
In your second example, the send happens before a receiver is ready so the send blocks and the program deadlocks.
You could fix the second example by making a buffered channel, but there is a chance you won't ever see the output from the goroutine as the program may exit (the main goroutine) before the output buffer is flushed. The goroutine may not even run as main exits before it can be scheduled.
First of all, go-routines run concurrently. In 1st example, the sub-goroutine has already started, but in 2nd example, the go-routine hasn't started yet when the send operation appears.
Think about line by line.
In 1st example, the sub-goroutine has started concurrently before the send operation appears on the main go-routine. As a result, when the the send operation happens, there is already an receiver (sub-goroutine) exists.
If you tweak the 1st example,
package main
import (
"fmt"
"time"
)
func main() {
ch01 := make(chan string)
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
// wait for start of sub-routine
time.Sleep(time.Second * 2)
fmt.Println("We are in the main goroutine")
ch01 <- "Hello"
// wait for the routine to receive and print the string
time.Sleep(time.Second * 2)
}
The output will be
We are in the sub goroutine
We are in the main goroutine
Hello
So, you can see that the sub-goroutine has already started.and it is waiting to receive on channel. When the main goroutine send string in channel, the sub-goroutine resumes and receives the signal.
But in 2nd example, The program has stuck in main go routine send operation, and the sub go routine has not started yet and will not start, because the program has not got that line yet. so there is no other receiver to receive the signal. So the program stuck in deadlock.
For unbuffered channels the go routine is blocked until there is no one to receive it. First there should be a go routine to receive the value from the channel and then a value to the channel is send. For the example when we are sending a value to channel it is required to create a buffered channel so that the value is saved into buffered until there is no one to receive it like this will work.
package main
import (
"fmt"
"time"
)
func main() {
ch01 := make(chan string, 10)
ch01 <- "Hello"
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
fmt.Println("We are in the main goroutine")
time.Sleep(1 * time.Second)
}
Playground
Did that mean after ch01 <- "Hello" the main goroutine was immediately
blocked so that the sub goroutine had no chance to run? If it is true,
how should I understand the result of the first code example?(At first
in main goroutine, then in sub goroutine).
It's true. You understand things write. Order of evaluation of spawned goroutines unspecified and can only be controlled with sync tools(channels, mutexes). Sub goroutine in first example may as well Print() first in another environment. It's just unspecified.
Is there any API to let the main goroutine sleep forever?
In other words, I want my project always run except when I stop it.
"Sleeping"
You can use numerous constructs that block forever without "eating" up your CPU.
For example a select without any case (and no default):
select{}
Or receiving from a channel where nobody sends anything:
<-make(chan int)
Or receiving from a nil channel also blocks forever:
<-(chan int)(nil)
Or sending on a nil channel also blocks forever:
(chan int)(nil) <- 0
Or locking an already locked sync.Mutex:
mu := sync.Mutex{}
mu.Lock()
mu.Lock()
Quitting
If you do want to provide a way to quit, a simple channel can do it. Provide a quit channel, and receive from it. When you want to quit, close the quit channel as "a receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received".
var quit = make(chan struct{})
func main() {
// Startup code...
// Then blocking (waiting for quit signal):
<-quit
}
// And in another goroutine if you want to quit:
close(quit)
Note that issuing a close(quit) may terminate your app at any time. Quoting from 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.
When close(quit) is executed, the last statement of our main() function can proceed which means the main goroutine can return, so the program exits.
Sleeping without blocking
The above constructs block the goroutine, so if you don't have other goroutines running, that will cause a deadlock.
If you don't want to block the main goroutine but you just don't want it to end, you may use a time.Sleep() with a sufficiently large duration. The max duration value is
const maxDuration time.Duration = 1<<63 - 1
which is approximately 292 years.
time.Sleep(time.Duration(1<<63 - 1))
If you fear your app will run longer than 292 years, put the above sleep in an endless loop:
for {
time.Sleep(time.Duration(1<<63 - 1))
}
It depends on use cases to choose what kind of sleep you want.
#icza provides a good and simple solution for literally sleeping forever, but I want to give you some more sweets if you want your system could shutdown gracefully.
You could do something like this:
func mainloop() {
exitSignal := make(chan os.Signal)
signal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM)
<-exitSignal
systemTeardown()
}
And in your main:
func main() {
systemStart()
mainloop()
}
In this way, you could not only ask your main to sleep forever, but you could do some graceful shutdown stuff after your code receives INT or TERM signal from OS, like ctrl+C or kill.
Another solution to block a goroutine. This solution prevents Go-Runtime to complain about the deadlock:
import "time"
func main() {
for {
time.Sleep(1138800 * time.Hour)
}
}