I'm learning Go right now using and one of my first projects is a simple ping script. Essentially I want to ping a bunch of urls, and on response of each one wait XXX number of seconds then ping again. Here is the abridged code:
func main() { // read our text file of urls f, err := ioutil.ReadFile(urlFile) if err != nil { log.Print(err) } urlStrings := []string{} urlStrings = strings.Split(string(f), "\n") for _, v := range urlStrings { go ping(v) } // output logs to the terminal // channel is global for i := range c { fmt.Println(i) } } func ping(url string) { // for our lag timer start := time.Now() // make our request _, err := http.Get(url) if err != nil { msg := url + " Error:" + err.Error() fmt.Println(msg) c <- msg reportError(msg) } else { lag := time.Since(start) var msg string // running slow if lag > lagThreshold*time.Second { msg = url + " lag: " + lag.String() reportError(msg) } msg = url + ", lag: " + lag.String() c <- msg } time.Sleep(pingInterval * time.Second) go ping(url) // is this acceptable? }
On my Get request I was previously calling defer res.Body.Close() but that was panicing after the app ran for awhile. I assumed that the defer could not call the Close() on the response until the goroutine had been garbage collected and the res no longer existed.
That got me thinking if by calling a goroutine inside of a goroutine was best practice or if I as causing the function to never exit, and then a defer would only be called once the goroutine was garbage collected.
Goroutines are functions or methods that run concurrently with other functions or methods. Goroutines can be thought of as lightweight threads. The cost of creating a Goroutine is tiny when compared to a thread. Hence it's common for Go applications to have thousands of Goroutines running concurrently.
Goroutines are useful when you want to do multiple things simultaneously. For example, if you have ten things you want to do at the same time, you can do each one on a separate goroutine, and wait for all of them to finish.
Typically, you pass the goroutine a (possibly separate) signal channel. That signal channel is used to push a value into when you want the goroutine to stop. The goroutine polls that channel regularly. As soon as it detects a signal, it quits.
One goroutine can't forcibly stop another. To make a goroutine stoppable, let it listen for a stop signal on a dedicated quit channel, and check this channel at suitable points in your goroutine.
That is fine. It's perfectly acceptable to call a goroutine from another goroutine. The calling goroutine will still exit and the new goroutine will go on it's merry way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With