"Select" statement inside of goroutine with for loop - for-loop

Could somebody please explain, why if goroutine has endless for loop and select inside of the loop, a code in the loop is run only one time?
package main
import (
"time"
)
func f1(quit chan bool){
go func() {
for {
println("f1 is working...")
time.Sleep(1 * time.Second)
select{
case <-quit:
println("stopping f1")
break
}
}
}()
}
func main() {
quit := make(chan bool)
f1(quit)
time.Sleep(4 * time.Second)
}
Output:
f1 is working...
Program exited.
But if "select" is commented out:
package main
import (
"time"
)
func f1(quit chan bool){
go func() {
for {
println("f1 is working...")
time.Sleep(1 * time.Second)
//select{
//case <-quit:
//println("stopping f1")
//break
//}
}
}()
}
func main() {
quit := make(chan bool)
f1(quit)
time.Sleep(4 * time.Second)
}
Output:
f1 is working...
f1 is working...
f1 is working...
f1 is working...
f1 is working...
https://play.golang.org/p/MxKy2XqQlt8

A select statement without a default case is blocking until a read or write in at least one of the case statements can be executed. Accordingly, your select will block until a read from the quit channel is possible (either of a value or the zero value if the channel is closed). The language spec provides a concrete description of this behavior, specifically:
If one or more of the communications [expressed in the case statements] can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.
Other code issues
Caution! break applies to the select statement
However, even if you did close the quit channel to signal shutdown of your program, your implementation would likely not have the desired effect. A (unlabelled) call to break will terminate execution of the inner-most for, select or switch statement within the function. In this case, the select statement will break and the for loop will run through again. If quit was closed, it will run forever until something else stops the program, otherwise it will block again in select (Playground example)
Closing quit will (probably) not immediately stop the program
As noted in the comments, the call to time.Sleep blocks for a second on each iteration of the loop, so any attempt to stop the program by closing quit will be delayed for up to approximately a second before the goroutine checks quit and escapes. It is unlikely this sleep period must complete in its entirety before the program stops.
More idiomatic Go would block in the select statement on receiving from two channels:
The quit channel
The channel returned by time.After – this call is an abstraction around a Timer which sleeps for a period of time and then writes a value to the provided channel.
Resolution
Solution with minimal changes
A resolution to fix your immediate issue with minimal changes to your code would be:
Make the read from quit non-blocking by adding a default case to the select statement.
Ensuring the goroutine actually returns when the read from quit succeeds:
Label the for loop and use a labelled call to break; or
return from the f1 function when it is time to quit (preferred)
Depending on your circumstances, you may find it more idiomatic Go to use a context.Context to signal termination, and to use a sync.WaitGroup to wait for the goroutine to finish before returning from main.
package main
import (
"fmt"
"time"
)
func f1(quit chan bool) {
go func() {
for {
println("f1 is working...")
time.Sleep(1 * time.Second)
select {
case <-quit:
fmt.Println("stopping")
return
default:
}
}
}()
}
func main() {
quit := make(chan bool)
f1(quit)
time.Sleep(4 * time.Second)
close(quit)
time.Sleep(4 * time.Second)
}
Working example
(Note: I have added an additional time.Sleep call in your main method to avoid this returning immediately after the call to close and terminating the program.)
Fixing the sleep blocking issue
To fix the additional issue regarding the blocking sleep preventing immediate quit, move the sleep to a timer in the select block. Modifying your for loop as per this playground example from the comments does exactly this:
for {
println("f1 is working...")
select {
case <-quit:
println("stopping f1")
return
case <-time.After(1 * time.Second):
// repeats loop
}
}
Related literature
Go-by-example: Non-blocking channel operations
Dave Cheney's Channel axioms, specifically the fourth axiom "A receive from a closed channel returns the zero value immediately."

Related

Stop a goroutine if it is running

I have a question similar to How to stop a goroutine with a small twist. I don't know for sure if the goroutine is running.
var quit = make(chan bool)
func f1() {
go func() {
t := time.NewTimer(time.Minute)
select {
case <-t.C:
// Do stuff
case <-quit:
return
}
}()
}
func f2() {
quit <- true
}
If f2() is called less than a minute after f1(), then the goroutine returns. However, if it is called later than one minute, the goroutine will have already returned and f2() would block.
I want f2() to cancel the goroutine if it is running and do nothing otherwise.
What I'm trying to achieve here is to perform a task if and only if it is not canceled within a minute of creation.
Clarifications:
There is nothing to stop f2() from being called more than once.
There is only one goroutine running at a time. The caller of f1() will make sure that it's not called more than once per minute.
Use contexts.
Run f1 with the context which may be cancelled.
Run f2 with the associated cancellation function.
func f1(ctx context.Context) {
go func(ctx context.Context) {
t := time.NewTimer(time.Minute)
select {
case <-t.C:
// Do stuff
case <-ctx.Done():
return
}
}(ctx)
}
func f2(cancel context.CancelFunc) {
cancel()
}
And later, to coordinate the two functions, you would do this:
ctx, cancel := context.WithCancel(context.Background())
f1(ctx)
f2(cancel)
You can also experiment with the context.WithTimeout function to incorporate externally-defined timeouts.
In the case where you don't know whether there is a goroutine running already, you can initialize the ctx and cancel variables like above, but don't pass them into anything. This avoids having to check for nil.
Remember to treat ctx and cancel as variables to be copied, not as references, because you don't want multiple goroutines to share memory - that may cause a race condition.
You can give the channel a buffer size of 1. This means you can send one value to it without blocking, even if that value is not received right away (or at all).
var quit = make(chan bool, 1)
I think the top answer is better, this is just another solution that could translate to other situations.

Why write channel blocked in spite of a goroutine is selecting on this channel?

I am confused about the following code, I write down some comment in the code which point out my confusion. And there is a result of execution at the end of the code, I also write down what result I expect.
package main
import (
"fmt"
"time"
)
func sendRPC() bool {
time.Sleep(5 * time.Second)
return true
}
func main() {
done := make(chan struct{})
ch := make(chan bool)
go func() { // goroutine A
select {
case ch <- sendRPC():
fmt.Println("RPC return")
case <-done:
fmt.Println("exit")
}
}()
select {
case <-ch:
case <-time.After(1000 * time.Millisecond):
fmt.Println("timeout")
if len(done) == 0 {
fmt.Println("1")
// here write done channel will block until sendRPC() return, why?
// I expect that the write is nonblock because goroutine A is select on done channel.
done <- struct{}{}
fmt.Println("2")
}
}
// result:
// timeout (after about 1 second)
// 1
// exit (after about 5 seconds, I expect that it is printed after about 1 second too.)
// 2
}
The specification says:
For all the cases in the statement, the channel operands of receive operations and the channel and right-hand-side expressions of send statements are evaluated exactly once, in source order, upon entering the "select" statement. The result is a set of channels to receive from or send to, and the corresponding values to send. Any side effects in that evaluation will occur irrespective of which (if any) communication operation is selected to proceed.
The set of channels for the select in goroutine A waits on the evaluation of sendRPC(). It may help to look at this equivalent goroutine:
go func() { // goroutine A
v := sendRPC() // waits for 5 seconds
select {
case ch <- v:
fmt.Println("RPC return")
case <-done:
fmt.Println("exit")
}
}()
The receive on done is delayed for 5 seconds.

go routine: does select really pick a random case?

Context: https://tour.golang.org/concurrency/5
Hello everyone, I am learning Go following the above link.
The description says "It chooses one at random if multiple are ready."
However, after making the main routine waiting for 2 second, before calling func fibonacci. The channels should be the following after 2 sec:
c: 10 calls to get value from the channel
quit: 0
It looks to me both channels are ready. If "It chooses one at random if multiple are ready" is true, then there is a 50% chance that the first call on the case in fibonacci will get the 0 from the quit channel. However, it is not the case. All 10 numbers will always get printed out before quitting. Hence it does not look like the selection is random. Am I missing something?
package main
import "fmt"
import "time"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
time.Sleep(2 * time.Second)
fibonacci(c, quit)
}
In addition, the next page:
https://tour.golang.org/concurrency/6
It looks like the default code should print out either tick. or BOOM! at 500 milli second. However, only BOOM! is printed, always. If I changed the time in the default from 50 to 55, then both tick and BOOM get printed. Why is this? Does a After take precedence over a Tick in a select?
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(55 * time.Millisecond)
}
}
}
I think you're mistaken about what's happening in your main method... I'm gonna break down what I think is going on for clarity
func main() {
c := make(chan int)
quit := make(chan int) // make a couple channels
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c) // blocked here in goroutine
}
quit <- 0
}() // go func { ... }() - you're both writing this closure and invoking it as a goroutine
time.Sleep(2 * time.Second) // sleep for 2 seconds
fibonacci(c, quit) // call fibonacci passing in the channels
}
so what's actually happened here is you've called this closure as a goroutine then wait 2 seconds during which your goroutine is still sitting in the body of the for loop waiting to receive on c, you call fibonacci which executes as you expect going into the for-select, at which point you keep hitting that code on every iteration of the loop c <- x (it receives, i gets incremented, you receive again, next value until the loop is over due to i == 10). then you proceed to the next line and send on the quit channel, the select executes that condition and your program exits.
As far as what executes first the language spec says;
Execution of a "select" statement proceeds in several steps:
1) For all the cases in the statement, the channel operands of receive
operations and the channel and right-hand-side expressions of send
statements are evaluated exactly once, in source order, upon entering
the "select" statement. The result is a set of channels to receive
from or send to, and the corresponding values to send. Any side
effects in that evaluation will occur irrespective of which (if any)
communication operation is selected to proceed. Expressions on the
left-hand side of a RecvStmt with a short variable declaration or
assignment are not yet evaluated. 2) If one or more of the
communications can proceed, a single one that can proceed is chosen
via a uniform pseudo-random selection. Otherwise, if there is a
default case, that case is chosen. If there is no default case, the
"select" statement blocks until at least one of the communications can
proceed. Unless the selected case is the default case, the respective
communication operation is executed. 3) If the selected case is a
RecvStmt with a short variable declaration or an assignment, the
left-hand side expressions are evaluated and the received value (or
values) are assigned. 4) The statement list of the selected case is
executed.
It's only psuedo random in race conditions, problem is you're not creating a race condition.
In the first snippet of your code, quit is never ready before the for loop. And, in every iteration of the loop, c is ready, and will block until a number is sent through. So there is really nothing select can do but write to c. It does not matter at all if you sleep two seconds.
The second piece of code is not bugged. The select does randomly pick a case indeed. However, Go Playground has a fixed random generator, which means, on Playground, select will always pick one certain case in every run.
You created an unbuffered chan:
c := make(chan int)
This means that anything reading from the chan is going to block until something is written to it. And anything writing to the chan is going to block until something reads from it.
Thus in this code:
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
the <-c blocks until something is put on c. So it sits there waiting until after your time.Sleep() completes, and gets to:
case c <- x:
upon which it alternates blocking back and forth reading one value, writing one value, until it reads 10 values, and then it sends 0 to quit.
To create a buffered chan, you need to specify a size for the buffer.
c := make(chan int, 10)
But note, that even if you do this, it's still not going to behave as you expect, as you're reading all 10 values before you write to quit. You need to put the writers in the same place, and the readers in the same place, not mixing them up.

Go: Act on Signal while not Blocking Operations

I want to fire the ps command continuously in a goroutine to monitor mem and cpu usages. I didn't use top because top doesn't allow me to select columns as ps does. This goroutine needs to receive a stop signal to stop the command, but I don't know how not to block running the command while waiting the signal. For top I can do:
top := exec.Command("top")
<-stop // blocking
top.Process.Signal(os.Kill)
But for ps if I do:
ps := exec.Command("ps")
for {
ps.Run()
<-stop
}
The above code will block on stop. I want to keep firing ps.Run(), while being able to stop when a stop signal is ready. Thanks.
One way that you could achieve this is by utilizing the for/select timeout idiom, there are a couple of similar methods of doing this. Take this trivial example:
package main
import (
"fmt"
"time"
)
func main() {
abort := make(chan struct{})
go func() {
for {
select {
case <-abort:
return
case <-time.After(1 * time.Second):
// replace fmt.Println() with the command you wish to run
fmt.Println("tick")
}
}
}()
// replace time.Sleep() with code waiting for 'abort' command input
time.Sleep(10 * time.Second)
abort <- struct{}{}
}
To modify this example to work in your circumstance place the code that you want to run in the <-time.After(): case, which (in this instance) will run once per second, if no other case is available to receive for that duration. And instead of time.Sleep() which I placed at the end, put the code that will interrupt the <-time.After(): case, sending <- struct{}{} on the abort channel (or whatever you name it).
NOTE: In an earlier version of this answer I had abort as a chan bool, as I like the clarity of <-abort true and don't consider chan struct{} to be as clear, I opted to change it in this example however, as <- struct{}{} isn't unclear, especially once you've gotten used to the pattern.
Also, if you want the command to execute on each iteration of the for loop and not wait for a timeout then you can make that case default:, remove <-time.After() and it will run on each iteration of the loop where another channel is not ready to receive.
You can play with this example in the playground if you'd like, although it will not allow syscalls, or the default: case example to be run in that environment.
To run it over and over, without sleep:
func run(stop <-chan struct{}) {
ps := exec.Command("ps")
for {
select {
case <-stop:
return
default:
ps.Run()
//processing the output
}
}
}
And then go run(stop). And to run it every 3 seconds (for example):
func run(stop <-chan struct{}) {
ps := exec.Command("ps")
tk := time.Tick(time.Second * 3)
for {
select {
case <-stop:
return
case <-tk:
ps.Run()
//processing the output
}
}
}

Interrupt a sleeping goroutine?

Is there a way in which I can execute, for example
time.Sleep(time.Second * 5000) //basically a long period of time
and then "wake up" the sleeping goroutine when I wish to do so?
I saw that there is a Reset(d Duration) in Sleep.go but I'm unable to invoke it.. Any thoughts?
There isn't a way to interrupt a time.Sleep, however, you can make use of time.After, and a select statement to get the functionality you're after.
Simple example to show the basic idea:
package main
import (
"fmt"
"time"
)
func main() {
timeoutchan := make(chan bool)
go func() {
<-time.After(2 * time.Second)
timeoutchan <- true
}()
select {
case <-timeoutchan:
break
case <-time.After(10 * time.Second):
break
}
fmt.Println("Hello, playground")
}
http://play.golang.org/p/7uKfItZbKG
In this example, we're spawning a signalling goroutine to tell main to stop pausing. The main is waiting and listening on two channels, timeoutchan (our signal) and the channel returned by time.After. When it receives on either of these channels, it will break out of the select and continue execution.

Resources