I have a function that calls another function that returns a chan array. I currently have a for loop looping over the range in the array which runs the program indefinitely outputting the channel updates as the come through.
func getRoutes() {
for r := range rtu {
if r.Type == 24 {
fmt.Printf("Route added: %s via %s\n",r.Dst.String(),r.Gw.String())
} else if r.Type == 25 {
fmt.Printf("Route deleted: %s via %s\n",r.Dst.String(),r.Gw.String())
}
}
}
When I call getRoutes() from main() everything works as planned though, it's blocking the application. I've tried calling go getRoutes() from main() though it appears as if the function isn't being called at all.
How can I run this function in the background in a non-blocking way using go routines?
When the primary goroutine at main exits, all goroutines you might have spawned will be orphaned and eventually die.
You could keep the main goroutine running forever with an infinite loop with for {}, but you might want to keep an exit channel instead:
exit := make(chan string)
// Spawn all you worker goroutines, and send a message to exit when you're done.
for {
select {
case <-exit:
os.Exit(0)
}
}
Update: Cerise Limón pointed out that goroutines are just killed immediately when main exits. I think this is supposed to be the officially specified behaviour.
Another update: The for-select works better when you have multiple ways to exit / multiple exit channels. For a single exit channel you could just do
<-exit
at the end instead of a for and select loop.
Although other people have answered this, I think their solutions can be simplified in some cases.
Take this code snippet:
func main() {
go doSomething()
fmt.Println("Done.")
}
func doSomething() {
for i := 0; i < 10; i++ {
fmt.Println("Doing something...")
time.Sleep(time.Second)
}
}
When main() begins executing, it spawns a thread to concurrently execute doSomething(). It then immediately executes fmt.Println("Done."), and the main() finishes.
When main() finishes, all other goroutines will be orphaned, and die.
To avoid this, we can put a blocking operation at the end of main() that waits for input from a goroutine. It's easiest to do this with a channel:
var exit = make(chan bool)
func main() {
go doSomething()
<-exit // This blocks until the exit channel receives some input
fmt.Println("Done.")
}
func doSomething() {
for i := 0; i < 10; i++ {
fmt.Println("Doing something...")
time.Sleep(time.Second)
}
exit<-true // Notify main() that this goroutine has finished
}
Your main() returns before getRoutes()-goroutine finishes. When main() returns, the program exits, thereby killing all the running goroutines. (It's also totally possible that main() returns even before the goroutine gets a chance to get scheduled by go runtime.)
If you want main() (or any other function) to wait for a group of goroutines to finish, you'd have to make the function explicitly wait somehow. There're multiple ways to do that. sync.WaitGroup.Wait() can be used to wait for a group of the goroutines to finish. You could also use channels to communicate when goroutines are done.
Related
I have to update thousands of structs with datas available on some remote servers. So, I have to deal with thousands of Goroutines querying these remote servers (http requests or db requests) to update the struct with the responses. But the update (or not) of the struct is depending of the results of other structs.
So I imagined a simple code in which the goroutines are running, each of them performs its own request, put the result in a global struct that contain any information retrieved by the goroutines and informs the main func that the first part of the job is done (waiting for the signal that every goroutines do the same before deciding of updating or not its struct.)
The goroutine should now waits for a signal of the main thread that all goroutines are done before deciding updating or not
the simplified code looks like that :
type struct StructToUpdate {
//some properties
}
type struct GlobalWatcher {
//some userful informations for all structs to update (or not)
}
func main() {
//retrieving all structs to update
structsToUpdates := foo()
//launching goroutines
c := make(chan bool)
for _,structToUpdate := range structsToUpdates {
go updateStruct(&structToUpdate,c)
}
//waiting for all goroutines do their first part of job
for i:=0; i<len(structsToUpdates); i++ {
<- c
}
//HERE IS THE CODE TO INFORM GOROUTINES THEY CAN RESUME
}
func updateStruct(s *StructToUpdate, c chan bool) {
result := performSomeRequest(s)
informGlobalWatcherOfResult(result)
c <- true //I did my job
//HERE IS THE CODE TO WAIT FOR THE SIGNAL TO RESUME
}
The question is : What the more performant / idiomatic / elegant wait to :
send a signal from the main script ?
wait for this signal from the goroutine ?
I can imagine 3 ways to do this
in a first way, I can imagine a global bool var resume := false that will be turned to true by the main func when all goroutines do the first part of job. In this case, each goroutine can use an ugly for !resume { continue }....
in a more idiomatic code, I can imagine do the same thing but instead of using a bool, I can use a context.WithValue(ctx, "resume", false) and pass it to goroutine, but I still have a for !ctx.Value("resume")
in a last more elegant code, I can imagine using another resume := make(chan bool) passed to the goroutine. The main func could inform goroutines to resume closing this chan with a simple close(resume). The goroutine will wait the signal with something than :
for {
_, more := <-resume
if !more {
break
}
}
//update or not
Is there any other good idea to do this ? One of the above solutions is better than others ?
I'm not sure if I understand your question completely, but a simple solution to blocking the main thread is with an OS signal ie.:
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGTERM)
// Blocks main thread
<-done
This doesn't have to be an OS signal, this could be a channel that receives a struct{}{} value from somewhere else in your runtime.
If you need to do this as a result of multiple go routines working, I'd look into using sync.WaitGroup.
OK. Thanks to #blixenkrone I found an elegant solution using WaitGroup !
Usually, we use a sync.WaitGroup to synchronize goroutines and be sure that they finish their job : you add "1" to the WaitGroup and then wait... Goroutines, when they finish their job, use the Done() function to decrement the Waitgroup counter. In fact, the Wait() function of the WaitGroup must act like a for loop, looking for its internal counter to become "0" to resume.
What I do is exactly the opposite !!! I create a WaitGroup and increment it to 1 in the main program before launching the goroutines, and pass it to them. The goroutine do their first past of job, notify the main program and then wait for the WaitGroup. When the main program get every notification of first part job, it release the waitgroup, then each goroutine can finish the job. Here is a squeleton of what I did :
func main() {
structsToUpdate := getStructs() //some func to get my structs
communication := make(chan bool)
//the waitgroup used to block the goroutine
var resume sync.WaitGroup
resume.Add(1) //The waitgroup will be blocked !!!
success := 0
for _,structToUpdate := range structsToUpdates {
go updateStruct(&structToUpdate,communication,&resume)
}
//waiting for all goroutines do their first part of job
for i:=0; i<len(structsToUpdates); i++ {
res := <- communication
if res {
success++
}
}
//all structs should have done with first part now... Resume their job !
resume.Done()
//receive second part job
for success != 0 {
<-communication
success--
}
}
func updateStruct(s *StructToUpdate, c chan bool, resume *sync.WaitGroup) {
//First part of the job
result, err := performSomeRequest(s)
if err != nil {
//something wrong happened
c <- false
return
}
informGlobalWatcherOfResult(result)
c <- true //I did my job
//wait for all goroutines do their first part job
resume.Wait()
//here the main program 'Done()' the WaitGroup so it resumes the execution of the goroutine
updateOrNotStruct() //Some operations...
c <- true
}
Even if I think the wg.Wait() func should call a for loop itself, I think this code is cleaner than the solutions a proposed above...
TL;DR: A typical case of all goroutines are asleep, deadlock! but can't figure it out
I'm parsing the Wiktionary XML dump to build a DB of words. I defer the parsing of each article's text to a goroutine hoping that it will speed up the process.
It's 7GB and is processed in under 2 minutes in my machine when doing it serially, but if I can take advantage of all cores, why not.
I'm new to threading in general, I'm getting a all goroutines are asleep, deadlock! error.
What's wrong here?
This may not be performant at all, as it uses an unbuffered channel, so all goroutines effectively end up executing serially, but my idea is to learn and understand threading and to benchmark how long it takes with different alternatives:
unbuffered channel
different sized buffered channel
only calling as many goroutines at a time as there are runtime.NumCPU()
The summary of my code in pseudocode:
while tag := xml.getNextTag() {
wg.Add(1)
go parseTagText(chan, wg, tag.text)
// consume a channel message if available
select {
case msg := <-chan:
// do something with msg
default:
}
}
// reading tags finished, wait for running goroutines, consume what's left on the channel
for msg := range chan {
// do something with msg
}
// Sometimes this point is never reached, I get a deadlock
wg.Wait()
----
func parseTagText(chan, wg, tag.text) {
defer wg.Done()
// parse tag.text
chan <- whatever // just inform that the text has been parsed
}
Complete code:
https://play.golang.org/p/0t2EqptJBXE
In your complete example on the Go Playground, you:
Create a channel (line 39, results := make(chan langs)) and a wait-group (line 40, var wait sync.WaitGroup). So far so good.
Loop: in the loop, sometimes spin off a task:
if ...various conditions... {
wait.Add(1)
go parseTerm(results, &wait, text)
}
In the loop, sometimes do a non-blocking read from the channel (as shown in your question). No problem here either. But...
At the end of the loop, use:
for res := range results {
...
}
without ever calling close(results) in exactly one place, after all writers finish. This loop uses a blocking read from the channel. As long as some writer goroutine is still running, the blocking read can block without having the whole system stop, but when the last writer finishes writing and exits, there are no remaining writer goroutines. Any other remaining goroutines might rescue you, but there are none.
Since you use the var wait correctly (adding 1 in the right place, and calling Done() in the right place in the writer), the solution is to add one more goroutine, which will be the one to rescue you:
go func() {
wait.Wait()
close(results)
}()
You should spin off this rescuer goroutine just before entering the for res := range results loop. (If you spin it off any earlier, it might see the wait variable count down to zero too soon, just before it gets counted up again by spinning off another parseTerm.)
This anonymous function will block in the wait variable's Wait() function until the last writer goroutine has called the final wait.Done(), which will unblock this goroutine. Then this goroutine will call close(results), which will arrange for the for loop in your main goroutine to finish, unblocking that goroutine. When this goroutine (the rescuer) returns and thus terminates, there are no more rescuers, but we no longer need any.
(This main code then calls wait.Wait() unnecessarily: Since the for didn't terminate until the wait.Wait() in the new goroutine already unblocked, we know that this next wait.Wait() will return immediately. So we can drop this second call, although leaving it in is harmless.)
The problem is that nothing is closing the results channel, yet the range loop only exits when it closes. I've simplified your code to illustrate this and propsed a solution - basically consume the data in a goroutine:
// This is our producer
func foo(i int, ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
ch <- i
fmt.Println(i, "done")
}
// This is our consumer - it uses a different WG to signal it's done
func consumeData(ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
for x := range ch {
fmt.Println(x)
}
fmt.Println("ALL DONE")
}
func main() {
ch := make(chan int)
wg := sync.WaitGroup{}
// create the producers
for i := 0; i < 10; i++ {
wg.Add(1)
go foo(i, ch, &wg)
}
// create the consumer on a different goroutine, and sync using another WG
consumeWg := sync.WaitGroup{}
consumeWg.Add(1)
go consumeData(ch,&consumeWg)
wg.Wait() // <<<< means that the producers are done
close(ch) // << Signal the consumer to exit
consumeWg.Wait() // << Wait for the consumer to exit
}
I have a code excerpt of a main running a go routine below. Why does this NOT happen: the main exits after it receives the done and before job return, which would make the child process zombie. Any reference to golang docs would be helpful.
func main() {
var jobDone = make(chan bool)
go job(jobDone)
<-jobDone
}
func job(done chan bool) {
for {
select {
case <-someOtherGlobalChannel:
//Please ignore this case/channel
fmt.Println("SOmeOtherChannel received")
default:
if check_somthing_expression {
done <- true
return
}
}
}
}
With these changes, your main will exit after the done channel
package main
import (
"fmt"
)
func main() {
var jobDone = make(chan bool)
go job(jobDone)
<-jobDone
}
func job(done chan bool) {
for {
select {
case <-someOtherGlobalChannel:
//Please ignore this case/channel
fmt.Println("SOmeOtherChannel received")
default:
if check_somthing_expression {
done <- true
return
}
}
}
}
Zombie Process
"...which would make the child process zombie"
go job() does not start a separate process, it starts another goroutine. You have a main goroutine, and a job goroutine in this program. Language spec:
A "go" statement starts the execution of a function call as an independent concurrent thread of control, or goroutine, within the same address space.
Therefore you will not be creating a Unix zombie process.
Main Not Exiting Before Job
"Why does this NOT happen: the main exits after it receives the done and before job return...?"
Reason #1: The Receive Operations are Blocking Both Goroutines
(1) Because there's no send statement on channel done in job.
<-done
is a receive operation. See "Receive operator" in Go spec:
For an operand ch of channel type, the value of the receive operation <-ch is the value received from the channel ch.
See also "Send statements" in Go spec:
ch <- 3 // send value 3 to channel ch
You need a send statement. E.g.:
done <- true
More explanatory text and examples are available in the Go Tour and Effective Go.
...And there's a second reason:
Reason #2: There's Nothing To Do Between Send and Return
(2) Because, even if you change the receive operation to a send statement, there's nothing to do in the job goroutine between when it sends on the channel and it returns, so it's not likely for any time to pass from one to the next. If you want that to happen, add a sleep in job using the time package:
done <- true
time.Sleep(time.Second * 30)
return
you need to put some bool message to your done channel,then the <-jobDone
} can get some message to finish the block
I wonder what happens to goroutines called from another goroutine when it returns. Do they continue running or get terminated?
Here is a sample code to show what I mean:
func func() {
// Doing something
}
func func2() {
go func()
// Doing things that end with a return
}
func main() {
go func2()
}
what happens to func() goroutine when func2() goroutine returns?
You can make an experiment on excellent https://play.golang.org playground!
I recommend experiment there - it helps very much with golang studying.
https://play.golang.org/p/OJ9sgakV-S
I've added 2 second delay, because if program exit too quickly, you 'll not see results from goroutines.
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)
}
}