exiting multiple go routines waiting on an unbuffered channel - go

I was trying to exit multiple Goroutines Simultaneously.
According to https://www.godesignpatterns.com/2014/04/exiting-multiple-goroutines-simultaneously.html
there is a well defined way to do it.
Another approach i see is the following
package main
import (
"fmt"
"time"
)
func main() {
var inCh chan int = make(chan int, 100)
var exit chan bool = make(chan bool)
for i := 0; i < 20; i++ {
go func(instance int) {
fmt.Println("In go routine ", instance)
for {
select {
case <-exit:
fmt.Println("Exit received from ", instance)
exit <- true
return
case value := <-inCh:
fmt.Println("Value=", value)
}
}
}(i)
}
time.Sleep(1 * time.Second)
exit <- true
<-exit // Final exit
fmt.Println("Final exit")
}
But I am confused and i really don't get it why the unbuffered channel at the end is executed as a last statement.
In reality I have 20 go routines listening for exit channel. Randomly one will receive it and send it to another.
Why always the reception within go routines is taking place and only when all of them are finished the channel reception with comment "// Final Exit" will execute ?
I will really appreciate if someone can give me an explanation.

Use close() for cancelation as shown in the linked article.
The code in question is not guaranteed to work. Here's a scenario where it fails:
One goroutine is ready to receive from exit. All other goroutines busy somewhere else.
The value sent by main is received by the ready goroutine.
That goroutine sends a value to exit that is received by main().
The other goroutines do not exit because no more values are sent to exit. See this playground example that uses time.Seep to induce the problem scenario.
Why always the reception within go routines is taking place and only when all of them are finished the channel reception with comment "// Final Exit" will execute ?
The program executes as if the channel maintains an ordered queue of waiting goroutines, but there's nothing in the specification that guarantees that behavior. Even if the channel has an ordered queue, the program can encounter the scenario above if a goroutine is doing something other than waiting on receive from exit.

If you notice the output of you program
In go routine 6
In go routine 0
In go routine 7
.
.
Exit received from 6
Exit received from 0
Exit received from 7
.
.
Final exit
They get called in the same( or almost the same) order of how they were started. If none of your Go routines are busy the first one registered will be used. This is just an implementation of the runtime and I would not count on this behavior.
Your final exit was the last channel to be listened on so it is used last.
If you remove the time.Sleep after your loop your final exit will get called almost immediately and most of your go routines will not receive the exit signal
Output with out time.Sleep (will very between runs)
In go routine 0
Exit received from 0
In go routine 1
In go routine 2
In go routine 3
In go routine 4
In go routine 5
In go routine 6
In go routine 7
In go routine 14
In go routine 15
In go routine 16
In go routine 17
In go routine 18
In go routine 19
Final exit

Consider this slight modification.
package main
import (
"fmt"
)
func main() {
var exit chan int = make(chan int)
var workers = 20
for i := 0; i < workers; i++ {
go func(instance int) {
fmt.Println("In go routine ", instance)
for {
select {
case i := <-exit:
fmt.Println("Exit", i, "received from ", instance)
exit <- i-1
return
}
}
}(i)
}
exit <- workers
fmt.Println("Final exit:", <-exit)
}
Here, I've done 3 things: First, I removed the unused channel, for brevity. Second, I removed the sleep. third, I changed the exit channel to an int channel that is decremented by every pass. If I pass the number of workers in, any value other than 0 from the "Final" message indicates dropped workers.
Here's one example run:
% go run t.go
In go routine 8
In go routine 5
In go routine 0
In go routine 2
Exit 20 received from 8
Exit 19 received from 5
Final exit: 18
In go routine 13
When main calls time.Sleep it doesn't get scheduled until the sleep is over. The other goroutines all have this time to set up their channel readers. I can only assume, because I can't find it written anywhere, that channel readers are likely to be queued in roughly chronological error - thus, the sleep guarantees that main's reader is the last.
If this is consistent behavior, it certainly isn't reliable.
See Multiple goroutines listening on one channel for many more thoughts on this.

Related

Code for stopping a loop doesn't work

I am trying to implement a stop to a loop in Go.
The inspiration from the code I have right now is from here:
how to kill goroutine
However, I've not been able to get my code to behave as expected. The simplified version of my code from a complex code base is this:
package main
import (
"fmt"
"time"
)
var quit chan struct{}
var send chan int
func quitroutine() {
for {
select {
case cnt := <-send:
fmt.Println(cnt)
if cnt == 5 {
quit <- struct{}{}
}
}
}
}
func runLoop() {
cnt := 0
for {
select {
case <-quit:
fmt.Println("quit!")
default:
fmt.Println("default")
}
fmt.Println("inloop")
time.Sleep(1 * time.Second)
cnt++
send <- cnt
}
}
func main() {
quit = make(chan struct{})
send = make(chan int)
go quitroutine()
runLoop()
fmt.Println("terminated")
}
This code crashes:
default
inloop
5
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.runLoop()
/tmp/t.go:37 +0x1a6
main.main()
/tmp/t.go:45 +0xa4
goroutine 5 [chan send]:
main.quitroutine()
/tmp/t.go:18 +0x10e
created by main.main
/tmp/t.go:44 +0x9f
exit status 2
Questions:
Why does it crash at all after cnt is 5? quitroutine only writes to the quitchannel if cnt == 5, but doesn't terminate itself. While runLoop, if it receives on the quit channel, should just print "quit!" (which it doesn't), but not terminate itself.
Why don't I get the "quit!" output? Do I even get the quit channel?
How does this need to be implemented correctly
Just as Adrian has said, one of your goroutines is trying to send on quit, while the other is trying to send on send. To answer your questions:
When cnt == 5 the quitroutine begins attempting to send on quit. Because quit <- struct{}{} is not a select case, the goroutine will block until another tries to read from quit. The other goroutine is similarly stuck trying to do send <- cnt (when cnt = 6).
You never get the "quit!" output because that goroutine is stuck trying to do send <-cnt.
The simplest solution I see would be to adjust runLoop() so that the send <- cnt is a case in the select.
I'd change runLoop() to look like this:
func runLoop() {
cnt := 0
for {
select {
case <-quit:
fmt.Println("quit!")
case send <- cnt: // moved stuff here
fmt.Println("inloop")
time.Sleep(1 * time.Second)
cnt++
default:
fmt.Println("default")
}
// stuff used to be here
}
}
This gives me output (until I killed the program):
default
inloop
0
inloop
1
inloop
2
inloop
3
inloop
4
inloop
5
quit!
default
inloop
6
inloop
7
Which seems to mostly be what you were after.
I'd also like to note that the select block in quitroutine() is unnecessary because it only has one case. Cleaning that up may make it more clear that that goroutine is stuck trying to send, and never takes the input from the send channel.
When you try to send on the quit channel, the quitroutine blocks until something reads from it.
At the same time, the main routine, in runloop, is trying to send the next number on the send channel. This also blocks, because the routine that would be reading from it is currently blocked trying to send on the quit channel.
Both routines are blocked, which is a deadlock, so the program crashes.
This could be fixed by either putting one or both channel send in a select, or making one or both channels buffered (even a buffer length of 1 would suffice).

Golang - Why use done channel

It's one of example code of Golang. But cannot understand why 'done' channel need in this case.
https://gobyexample.com/closing-channels
There is no reason to sent true to done channel. We can know jobs channel is done when "sent all jobs" message is printed, isn't it?
I deleted code that relative to done channel and result is still same.
https://play.golang.org/p/xOmzobFpTQ
No the result is not the same:
Your main goroutine exits before your received job goroutine in many situations (e.g. different CPU loads, and it is nondeterministic and system dependent behavior), so in that way you cannot guarantee that all jobs received, e.g. just Add
time.Sleep(500)
before
fmt.Println("received job", j)
to see this, try it on The Go Playground:
// _Closing_ a channel indicates that no more values
// will be sent on it. This can be useful to communicate
// completion to the channel's receivers.
package main
import (
"fmt"
"time"
)
// In this example we'll use a `jobs` channel to
// communicate work to be done from the `main()` goroutine
// to a worker goroutine. When we have no more jobs for
// the worker we'll `close` the `jobs` channel.
func main() {
jobs := make(chan int, 5)
//done := make(chan bool)
// Here's the worker goroutine. It repeatedly receives
// from `jobs` with `j, more := <-jobs`. In this
// special 2-value form of receive, the `more` value
// will be `false` if `jobs` has been `close`d and all
// values in the channel have already been received.
// We use this to notify on `done` when we've worked
// all our jobs.
go func() {
for {
j, more := <-jobs
if more {
time.Sleep(500)
fmt.Println("received job", j)
} else {
fmt.Println("received all jobs")
//done <- true
return
}
}
}()
// This sends 3 jobs to the worker over the `jobs`
// channel, then closes it.
for j := 1; j <= 3; j++ {
jobs <- j
fmt.Println("sent job", j)
}
close(jobs)
fmt.Println("sent all jobs")
// We await the worker using the
// [synchronization](channel-synchronization) approach
// we saw earlier.
//<-done
}
output:
sent job 1
sent job 2
sent job 3
sent all jobs
instead of:
sent job 1
received job 1
received job 2
sent job 2
sent job 3
received job 3
received all jobs
sent all jobs
See:
Goroutine does not execute if time.Sleep included
Why is time.sleep required to run certain goroutines?
Weird channel behavior in go
TL;DR: There is a race condition---You got lucky.
If you didn't have the done channel, then the output of the program is non-deterministic.
Depending on the thread execution order, the main thread may exit before the goroutine finished its processing thereby causing the goroutine to be killed mid way.
By forcing the main thread to read from the done channel, we're forcing the main thread to wait until there is some data to be consumed in the done channel. This gives us a neat synchronization mechanism wherein the goroutine informs the main thread that it is done by writing to the done channel. This in turn causes the main thread's blocking <- done to finish and causes the program to terminate.
I think the accepted answer did not go into the exact reasons why.
The go language belongs to the procedural paradigm, meaning that every instruction is executed linearly. When a go routine is forked from the main go routine, it goes off on its own little adventure, leaving the main thread to return.
The buffered channel has a capacity of 5, which means it will not block until the buffer is full. It will also block if it is empty (a channel with zero capacity is inherently unbuffered).
Since there are only 4 iterations (0 to <=3), the read operation will not block.
By instructing the main thread to read from the done channel, we're forcing the main thread to wait until there is some data to be consumed in the done channel. When the iteration is over, the else branch is executed and the write operation done <- true causes the release of the <- done read operation in the main thread. The read operation waits to pull the now inserted value off of done.
After reading from done, the main Go routine is no longer blocked, hence terminating successfully.
Sent doesn't mean the job is done, when the job take long time to
finish.
The jobs channel is buffered, so even the job is sent, the job may
not even received by the worker yet.

Go project's main goroutine sleep forever?

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)
}
}

Goroutine does not execute if time.Sleep included

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.

Is gorouines ignore channel's buffer size

Environment: OS X 10.8, Go 1.0.2
I make a channel with buffer-size 2, then if I write channel three times, it will throw error:
throw: all goroutines are asleep - deadlock!
Of course, it's correct.
BUT if I write channel four or more times in the goroutines, it works fine, why?
The channel's capacity is 2, why goroutines ignore that or forget the capacity setting?
I comment the read-channel codes, so no one will read channel and save the capacity. I also use time.Sleep to waiting for all goroutines finish their work.
please review following codes:
package main
//import "fmt"
func main() {
c := make(chan int, 2)
/*c <- 1
c <- 2
c <- 3*/
for i:=0; i<4; i++ {
go func(i int) {
c <- i
c <- 9
c <- 9
c <- 9
}(i)
}
time.Sleep(2000 * time.Millisecond)
/*for i:=0; i<4*2; i++ {
fmt.Println(<-c)
}*/
}
Would anyone please give some hits? thanks, guys.
When a channel is buffered, this means it will not block until the buffer is full. Once the buffer is full, the sending goroutine will block as it tries to add things to the channel.
This means that this will block:
c := make(chan int)
c <- 1 // Block here, this is unbuffered !
println(<-c)
And this will also block:
c := make(chan int, 2)
c <- 1
c <- 2
c <- 3 // Block here, buffer is full !
println(<-c)
But the point of goroutines and channel is precisely to run things concurrently, so this will work:
c := make(chan int)
go func() { c <- 1; }() // This will block in the spawned goroutine until...
println(<-c) // ... this line is reached in the main goroutine
And similarly:
c := make(chan int, 2)
go func() { // `go ...` spawns a goroutine
c <- 1 // Buffer is not full, no block
c <- 2 // Buffer is not full, no block
c <- 3 // Buffer is full, spawned goroutine is blocking until...
}()
println(<-c) // ... this line is reached in the main goroutine
In your example, you spawn four different goroutines, which all write four numbers to the same buffered channel. As the buffer is 2 < 16, they will end up blocking
But the crux of the matter is that the Go policy is to wait only for the main goroutine:
Program execution begins by initializing the main package and then invoking the function main. When the function main returns, the program exits. It does not wait for other (non-main) goroutines to complete.
This means that in your first example, the main goroutine was blocking when it reached line c <- 3. As no other goroutine was able to do anything which could potentially unblock it, the runtime detected that the program was deadlocked and reported an error.
In your second example however, spawned goroutines block, while the main continues quietly until it reaches the end of its execution, at which point all the (blocked) spawned goroutines are silently killed, and no error is reported.
val has given a good answer. I'd like to add an extra tip I've found useful.
When learning to use goroutines, use zero-buffered channels to start with. This way, when you make a mistake, you'll immediately get a deadlock, which you can learn from. You need to learn how to write code that doesn't deadlock, which means learning tricks like not having cyclic dependencies in the client-server relationships (assuming your goroutines are written as clients or servers).
Reasoning about the network without buffering is simpler, although this might not be obvious at first.
Buffering is really useful, but should be considered as a means to enhance performance.

Resources