Reputation: 8360
I'm trying to create a program that prints "Eat"
, "Work"
, "Sleep"
every 3rd, 8th, and 24th second respectively. Here is my code:
package main
import (
"fmt"
"time"
)
func Remind(text string, delay time.Duration) <-chan string { //channel only for receiving strings
ch := make(chan string) // buffered/unbuffered?
go func() {
for {
msg := "The time is " + time.Now().Format("2006-01-02 15:04:05 ") + text
ch <- msg
time.Sleep(delay) // waits according to specification
}
}()
return ch
}
func main() {
ch1 := Remind("Eat", 1000*1000*1000*3) // every third second
ch2 := Remind("Work", 1000*1000*1000*8) // every eighth second
ch3 := Remind("Sleep", 1000*1000*1000*24) // every 24th second
select { // chooses one channel that is not empty. Should run forever (?)
case rem1 := <-ch1:
fmt.Println(rem1)
case rem2 := <-ch2:
fmt.Println(rem2)
case rem3 := <-ch3:
fmt.Println(rem3)
}
}
The problem with it is that it stops running immediately after printing the time followed by "Eat"
. In other examples I have read, the select
statement goes on forever. Why doesn't it now?
Upvotes: 1
Views: 1299
Reputation: 417572
I don't know where you've read that the select
goes on forever, but it doesn't.
Once a case
is executed, the select
statement is "done". If none of the communication operations specified in case
s can proceed and there is no default
branch, select
will block, for as long as any of the com. ops can proceed. But once a case
is executed, select
does not repeat.
Read the relevant section from the spec: Select statements.
Put it in an endless for
to make it repeat forever:
for {
select { // chooses one channel that is not empty. Should run forever (?)
case rem1 := <-ch1:
fmt.Println(rem1)
case rem2 := <-ch2:
fmt.Println(rem2)
case rem3 := <-ch3:
fmt.Println(rem3)
}
}
As a sidenote:
You can create time.Duration
values much easier, using constants from the time
package:
ch1 := Remind("Eat", 3*time.Second) // every third second
ch2 := Remind("Work", 8*time.Second) // every eighth second
ch3 := Remind("Sleep", 24*time.Second) // every 24th second
You may also want to check out the time.Ticker
type which is for tasks similar to your Remind()
function.
Upvotes: 4
Reputation: 11551
select
in Go mostly resembles the switch control statement and is sometimes called communication switch. select
listens for incoming data on channels, but there could also be cases where a value is sent on a channel. In one word select
is used to get or send values on concurrently executing goroutines.
In your example because you are executing the current time in the main goroutine, it's always executed. But because the other goroutines are executed in the select statement these are not always get the chance to be executed, because once a case
is executed the channel blocks.
What select does:
Using a send operation in a select statement with a default case guarantees that the send will be non-blocking!
To run forever use it in a for loop:
package main
import (
"fmt"
"time"
)
func Remind(text string, delay time.Duration) <-chan string { //channel only for receiving strings
ch := make(chan string) // buffered/unbuffered?
go func() {
for {
msg := "The time is " + time.Now().Format("2006-01-02 15:04:05 ") + text
ch <- msg
time.Sleep(delay) // waits according to specification
}
}()
return ch
}
func main() {
ch1 := Remind("Eat", 1000*1000*1000*3) // every third second
ch2 := Remind("Work", 1000*1000*1000*8) // every eighth second
ch3 := Remind("Sleep", 1000*1000*1000*24) // every 24th second
for {
select { // chooses one channel that is not empty. Should run forever (?)
case rem1 := <-ch1:
fmt.Println(rem1)
case rem2 := <-ch2:
fmt.Println(rem2)
case rem3 := <-ch3:
fmt.Println(rem3)
}
}
}
http://play.golang.org/p/BuPqm3xsv6
Upvotes: 2