I've started messing around with Go, and I'm fascinated by go routines. I now wrote a simple test to see if I can change the value of a variable while I continuously print it out.
I now have the following code:
package main
import (
"fmt"
"time"
)
func change(c chan float64) float64 {
time.Sleep(2 * time.Second)
return 2.5
}
func main() {
s := 1.1
c := make(chan float64)
go change(c)
s = <-c
for {
fmt.Println(s)
time.Sleep(100 * time.Millisecond)
}
}
Unfortunately it ends in an error:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/home/kramer65/repos/go/src/messing_around/main.go:19 +0x7d
exit status 2
I searched around and found that this deadlock happens when the main function ends while goroutines didn't end yet. But since I have an endless loop I wouldn't know what else is wrong with my code.
What is wrong with this code, and how I can change the value of a variable while I continuously print it out?
It looks like you might have a misunderstanding on channels and go routines.
The line:
go change(c)
seems to indicate that the function change
is going to write to c
. However it ends up just returning a value after a period of time.
This value (2.5
) doesn't get received anywhere. Also, c
doesn't get written to anywhere. I suspect you intended the 2.5
to be written to the channel c
. The syntax for that is as follows:
c<-2.5
Therefore, if you change your change
function to:
func change(c chan float64) {
time.Sleep(2 * time.Second)
c <- 2.5
}
You should not see the deadlock anymore. Notice I am not returning a float64
anymore.
I made a playground to ensure this: https://play.golang.org/p/SgLiUmPpcAZ
Update for Comment
The 1.1
will always be overwritten by the value of the channel. If however you want to print s
's initial value (as stated in the comment), you will have to change the flow a bit and use a select
statement:
package main
import (
"fmt"
"time"
)
func change(c chan float64) {
time.Sleep(2 * time.Second)
c <- 2.5
}
func main() {
s := 1.1
c := make(chan float64)
go change(c)
for {
select {
case s = <-c:
default:
// c isn't ready yet
}
fmt.Println(s)
time.Sleep(100 * time.Millisecond)
}
}
Now that you have a select
statement, you can use it with a time.Ticker
as well:
ticker := time.NewTicker(100 * time.Millisecond)
for {
select {
case s = <-c:
case <-ticker.C:
fmt.Println(s)
default:
// c isn't ready yet
}
}