Need help to understand this weird bahaviour of go routines - go

I've following code using go routines:
package main
import (
"fmt"
"time"
)
func thread_1(i int) {
time.Sleep(time.Second * 1)
fmt.Println("thread_1: i: ",i)
}
func thread_2(i int) {
time.Sleep(time.Second * 1)
fmt.Println("thread_2: i: ",i)
}
func main() {
for i := 0; i < 100; i++ {
go thread_1(i)
go thread_2(i)
}
var input string
fmt.Scanln(&input)
}
I was expecting each go routine would wait for a second and then print its value of i.
However, both the go routines waited for 1 second each and printed all the values of i at once.
Another question in the same context is:
I've a server-client application where server spawns a receiver go routine to receive data from client one for each client connection. Then the receiver go routine spawns a worker go routine called processor to process the data. There could be multiple receiver go routines and hence multiple processor go routines.
In such a case some receiver and processor go routines may hog indefinitely.
Please help me understand this behaviour.

You span 100 goroutines running thread_1 and 100 goroutines running thread_2 in one big batch. Each of these 200 goroutines sleeps for one second and then prints and ends. So yes, the behavior is to be expected: 200 goroutines sleeping each 1 second in parallel and then 200 goroutines printing in parallel.
(And I do not understand your second question)

Related

Go channel readyness

I am trying to understand channels in Go. I have read that by default sends and receives block until both the sender and receiver are ready. But how do we figure out readyness of sender and receiver.
For example in the following code
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
The program will get stuck on the channel send operation waiting forever for someone to read the value. Even though we have a receive operation in println statement it ends up in a deadlock.
But for the following program
package main
import "fmt"
func main() {
ch := make(chan int)
go func () {
ch <- 1
}()
fmt.Println(<-ch)
}
The integer is passed successfully from go routine to main program. What made this program work? Why second works but first do not? Is go routine causing some difference?
Let's step through the first program:
// My notes here
ch := make(chan int) // make a new int channel
ch <- 1 // block until we can send to that channel
// keep blocking
// keep blocking
// still waiting for a receiver
// no reason to stop blocking yet...
// this line is never reached, because it blocks above forever.
fmt.Println(<-ch)
The second program splits the send off into its own line of execution, so now we have:
ch := make(chan int) // make a new int channel
go func () { // start a new line of execution
ch <- 1 // block this second execution thread until we can send to that channel
}()
fmt.Println(<-ch) // block the main line of execution until we can read from that channel
Since those two lines of execution can work independently, the main line can get down to fmt.Println and try and receive from the channel. The second thread will wait to send until it has.
The go routine absolutely makes a difference. The go routine that writes to the channel will be blocked until your main function is ready to read from the channel in the print statement. Having two concurrent threads, one that reads and one that writes fulfills the readiness on both sides.
In your first example, the single thread gets blocked by the channel write statement and will never reach the channel read.
You need to have a concurrent go routine to read from a channel whenever you write to it. Concurrency goes hand-in-hand with channel usage.

Understanding Go channel deadlocks

package main
import (
"fmt"
"time"
)
func main() {
p := producer()
for c := range p {
fmt.Println(c)
}
}
func producer() <-chan string {
ch := make(chan string)
go func() {
for i := 0; i < 5; i++ {
ch <- fmt.Sprint("hello", i)
time.Sleep(1 * time.Second)
}
// commented the below to show the issue
// close(ch)
}()
return ch
}
Running the above code will print 5 messages and then give a "all go routines are a sleep - deadlock error". I understand that if I close the channel the error is gone.
The thing I would like to understand is how does go runtime know that the code will be waiting infinitely on the channel and that there is nothing else that will be sending data into the channel.
Now if I add an additional go routine to the main() function.. it does not throw any error and keeps waiting on the channel.
go func() {
for {
time.Sleep(2 * time.Millisecond)
}
}()
So does this mean.. the go runtime is just looking for presence of a running go routine that could potentially send data into the channel and hence not throwing the deadlock error ?
If you want some more insight into how Go implements the deadlock detection, have a look at the place in the code that throws the "all goroutines are asleep - deadlock!": https://github.com/golang/go/blob/master/src/runtime/proc.go#L3751
It looks like the Go runtime keeps some fairly simple accounting on how many goroutines there are, how many are idle, and how many are sleeping for locks (not sure which one sleep on channel I/O will increment). At any given time (serialized with the rest of the runtime), it just does some arithmetic and checks if all - idle - locked > 0... if so, then the program could still make progress... if it's 0, then you're definitely deadlocked.
It's possible you could introduce a livelock by preventing a goroutine from sleeping via an infinite loop (like what you did in your experiment, and apparently sleep for timers isn't treated the same by the runtime). The runtime wouldn't be able to detect a deadlock in that case, and run forever.
Furthermore, I'm not sure when exactly the runtime checks for deadlocks- further inspection of who calls that checkdead() may yield some insight there, if you're interested.
DISCLAIMER- I'm not a Go core developer, I just play one on TV :-)
The runtime panics with the "all go routines are a sleep - deadlock error" error when all goroutines are blocked on channel and mutex operations.
The sleeping goroutine does not block on one of these operations. There is no deadlock and therefore no panic.

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

Gogoutine schedule algorithm

package main
import ()
func main() {
msgQueue := make(chan int, 1000000)
netAddr := "127.0.0.1"
token := make(chan int, 10)
for i := 0; i < 10; i++ {
token <- i
}
go RecvReq(netAddr, msgQueue)
for {
select {
case req := <-msgQueue:
go HandleReq(req, token)
}
}
}
func RecvReq(addr string,msgQueue chan int){
msgQueue<-//get from network
}
func HandleReq(msg int, token chan int) {
//step 1
t := <-token
//step 2
//codo here...(don't call runtime.parkļ¼‰
//step 3
//code here...(may call runtime.park)
//step 4
token <- t
}
System: 1cpu 2core
Go version:go1.3 linux/amd64
Problem description:
msgQueue revc request all the time by RecvReq,then the main goroutine create new goroutine all the time,but the waiting goroutine wait all the time.The first 10 goroutines stop at step 3,new goroutines followed stop at step 1.
Q1:How to make the waiting goroutine to run when new goroutine is being created all the time.
Q2:How to balance RevcReq and HandleReq? Revc msg rate is 10 times faster than Handle msg.
Alas this is not very clear from your question. But there are several issues here.
You create a buffered channel of size n then insert n items into it. Don't do this - or to be clearer, don't do this until you know it's needed. Buffered channels usually fall into the 'premature optimisation' category. Start with unbuffered channels so you can work out how the goroutines co-operate. When it's working (free of deadlocks), measure the performance, add buffering, try again.
Your select has only one guard. So it behaves just like the select wasn't there and the case body was the only code there.
You are trying to spawn off new goroutines for every message. Is this really what you wanted? You may find you can use a static mesh of goroutines, perhaps 10 in your case, and the result may be a program in which the intent is clearer. It would also give a small saving because the runtime would not have to spawn and clean up goroutines dynamically (however, you should be concerned with correct behaviour first, before worrying about any inefficiencies).
Your RecvReq is missing from the playground example, which is not executable.

Using Goroutines for background work inside an http handler

I thought I'd found an easy way to return an http response immediately then do some work in the background without blocking. However, this doesn't work.
func MyHandler(w http.ResponseWriter, r *http.Request) {
//handle form values
go doSomeBackgroundWork() // this will take 2 or 3 seconds
w.WriteHeader(http.StatusOK)
}
It works the first time--the response is returned immediately and the background work starts. However, any further requests hang until the background goroutine completes. Is there a better way to do this, that doesn't involve setting up a message queue and a separate background process.
I know this question was posted 4 years ago, but I hope someone can find this useful.
Here is a way to do that
There are something called worker pool https://gobyexample.com/worker-pools Using go routines and channels
But in the following code I adapt it to a handler. (Consider for simplicity I'm ignoring the errors and I'm using jobs as global variable)
package main
import (
"fmt"
"net/http"
"time"
)
var jobs chan int
func worker(jobs <-chan int) {
fmt.Println("Register the worker")
for i := range jobs {
fmt.Println("worker processing job", i)
time.Sleep(time.Second * 5)
}
}
func handler(w http.ResponseWriter, r *http.Request) {
jobs <- 1
fmt.Fprintln(w, "hello world")
}
func main() {
jobs = make(chan int, 100)
go worker(jobs)
http.HandleFunc("/request", handler)
http.ListenAndServe(":9090", nil)
}
The explanation:
main()
Runs the worker in background using a go routine
Start the service with my handler
note that the worker in this moment is ready to receive a job
worker()
it is a go routine that receives a channel
the for loop never ends because the channel is never closed
when a the channel contain a job, do some work (e.g. waits for 5 seconds)
handler()
writes to the channel to active a job
immediately returns printing "hello world" to the page
the cool thing is that you can send as many requests you want and because this scenario only contains 1 worker. the next request will wait until the previous one finished.
This is awesome Go!
Go multiplexes goroutines onto the available threads which is determined by the GOMAXPROCS environment setting. As a result if this is set to 1 then a single goroutine can hog the single thread Go has available to it until it yields control back to the Go runtime. More than likely doSomeBackgroundWork is hogging all the time on a single thread which is preventing the http handler from getting scheduled.
There are a number of ways to fix this.
First, as a general rule when using goroutines, you should set GOMAXPROCS to the number of CPUs your system has or to whichever is bigger.
Second, you can yield control in a goroutine by doing any of the following:
runtime.Gosched()
ch <- foo
foo := <-ch
select { ... }
mutex.Lock()
mutex.Unlock()
All of these will yield back to the Go runtime scheduler giving other goroutines a chance to work.

Resources