In the code below, iterations are runned two times.
Is it possible that "test2 <- true" is runned at the moment which is just between the first iteration and the second iteration?
I mean, is there a change to send true to "test2" when the first iteration is ended and the second iteration is not started?
package main
import "log"
import "time"
func main() {
test := make(chan bool, 1)
test2 := make(chan bool, 1)
go func() {
for {
select {
case <-test:
log.Println("test")
case <-test2:
log.Println("test2")
}
}
}()
test <- true
time.Sleep(1)
test2 <- true
time.Sleep(1)
}
Yes. Since your channels are buffered and can hold 1 value. the main execution flow can continue without your anonymous goroutine reading the value you send to the test
channel, and it can send a value on the test2
channel before the goroutine wakes up and read the value on the test
channel.
This is unlikely to happen, since you have a time.Sleep() call there to normally give time for the goroutine to execute, but there's no telling what'll happen in a corner case of your machine being very busy, being power suspended at an (un)lucky time or other things you didn't think about.
If your test
channel was unbuffered, the test <- true
statement would block until your goroutine received the value, and there would at least be no possibility for the goroutine to receive from test2
before receiving anything from the test
channel.
To add to nos' answer, you can simulate that case (where "test2 <- true
" is run at the moment which is just between the first iteration and the second iteration") easily enough by making your first message reception (case <- test
) wait one second.
case <-test:
log.Println("test")
time.Sleep(1 * time.Second)
By the time the anonymous goroutine wakes up, main()
has already sent its two messages to the two buffered channel (buffer means non-blokcing for one message), and exited.
If main()
exits, everything else, including the goroutine which was busy sleeping, stops.
See play.golang.org: the output would be:
2009/11/10 23:00:00 test
You wouldn't have the time to see test2
.
In order to make sure your goroutine can process both message, you need:
main()
to wait for said goroutine to finish. That is where the sync
package comes into play, using (for instance, this isn't the only solution) a WaitGroup
directive.
var wg sync.WaitGroup
wg.Add(1)
go func() {
// Decrement the counter when the goroutine completes.
defer wg.Done()
...
}
... // end of main():
// Wait for goroutine to complete.
wg.Wait()
the goroutine to actually exit at some time (instead of being stuck in the for
loop forever). See "In Go, does a break statement break from a switch/select?"
loop: <==========
for {
select {
case <-test:
log.Println("test")
time.Sleep(1 * time.Second)
case <-test2:
log.Println("test2")
break loop <==========
}
}
See play.golang.org: the message test2
is sent while the goroutine is sleeping after test1
, but main()
will wait (wg.Wait()
), and the goroutine will have its chance to read and print test2
one second later.
The output is:
2009/11/10 23:00:00 test
2009/11/10 23:00:01 test2 // one second later