18

I'm new to Go. Say I have a server listening to HTTP request, and at the same time I need to check Redis notification so I can update data. Below is an example:

func checkExpire() {
    for {
        switch msg := pubSubConn.Receive().(type) {
        case redis.Message:
        ...
    }
}

server.ListenAndServe()

Does simply putting checkExpire into a goroutine a good solution?

go func() {
    for {
        switch msg := pubSubConn.Receive().(type) {
        case redis.Message:
        ...
    }
}()
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
laike9m
  • 18,344
  • 20
  • 107
  • 140
  • 1
    Why not? That should be perfectly fine. – tier1 Oct 06 '16 at 17:54
  • I'm not sure what you're asking, goroutines are how you run something concurrently in Go. What else would you do? – JimB Oct 06 '16 at 17:56
  • Just be aware that goroutines do not prevent the main process from exiting. You may need to block with `for {}` at the end of main(). *edit* actually server.ListenAndServe should block – Plato Oct 06 '16 at 18:06
  • 1
    @Plato Sorry, I should put `ListenAndServe` below `checkExpire`. – laike9m Oct 07 '16 at 04:03

1 Answers1

31

Yes, and remember that main is a goroutine too, here is the working code:

package main

import (
    "fmt"
    "net/http"
    "time"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func checkExpire() {
    for {
        // do some job
        fmt.Println(time.Now().UTC())
        time.Sleep(1000 * time.Millisecond)
    }
}

func main() {
    go checkExpire()
    http.HandleFunc("/", handler) // http://127.0.0.1:8080/Go
    http.ListenAndServe(":8080", nil)
}

Run the code and open your browser.


And never use Empty loop (for{}) see:
Difference between the main goroutine and spawned goroutines of a Go program

Empty loop uses 100% of a CPU Core, to wait for some operation depending to the use case you may use:
- sync.WaitGroup like this
- select {} like this
- channels
- time.Sleep

Community
  • 1
  • 1
  • Though I've known what to do before you answer, I'll still accept yours. Thx. – laike9m Oct 07 '16 at 15:54
  • 4
    Instead of a for {} loop with a sleep, you might be better off with a `for _ := time.Tick(...) {}` loop and avoid the sleep. – dma May 23 '18 at 20:45
  • It is perfectly fine to use empty for in GO to block a go-routine. In fact, sometimes when you want to do periodic tasks, it is your only way to do that. E.g., ``` for { select{ case <-ticker.C: // do something after every ticker time case <-anotherChan: // do other thing } } ``` – adonese Sep 09 '19 at 20:38
  • 1
    @adonese that's not empty, your loop is perfectly fine and is one of the things the answer suggests. "Empty" here means literally `for {}`. – scenia Oct 12 '19 at 16:52
  • I believe the comment i replied to suggested to use `select` instead of a `for{}` for blocking. – adonese Oct 14 '19 at 20:09