Who is Goroutine

轻量级线程-协程

How to use Goroutine

https://dave.cheney.net/practical-go/presentations/qcon-china.html#_concurrency

  • Keep yourself busy or do the work yourself
    • 如果你的Goroutine在另一个Goroutine获得结果之前无法取得进展,那么通常情况下,自己做,比委派出去更简单
  • Never satart a Goroutine without knowing when it will stop
    • 如果要委派出去Goroutine,应该感知到Goroutine结束
  • Leave concurrency to the caller
    • 并发交给调用者

      Rule

      每次执行 go xxx 思考

  1. 什么时候Goroutine结束?
  2. 如何让某个Goroutine结束?
  3. Goroutine由调用者 go

Bad Code

  1. func main() {
  2. go func() {
  3. test()
  4. }()
  5. select {}
  6. }
  7. func test() {
  8. // xxxx xxxx xxxx
  9. }
  1. func main() {
  2. Go(test)
  3. select {}
  4. }
  5. func test() {
  6. // xxxx xxxx xxxx
  7. }
  8. func Go(f func()) {
  9. go func() {
  10. if err := recover(); err != nil {
  11. fmt.Println(err)
  12. }
  13. f()
  14. }()
  15. }
  1. func main() {
  2. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  3. fmt.Fprintln(w, "Hello")
  4. })
  5. go func() {
  6. if err := http.ListenAndServe(":8080", nil); err != nil {
  7. log.Fatal(err)
  8. }
  9. }()
  10. select {}
  11. }
  1. func main() {
  2. mux := http.NewServeMux()
  3. mux.HandleFunc("/", func(resp http.ResponseWriter, req *http.Request) {
  4. fmt.Fprintln(resp, "Hello, QCon!")
  5. })
  6. go http.ListenAndServe("127.0.0.1:8001", http.DefaultServeMux) // debug
  7. http.ListenAndServe("0.0.0.0:8080", mux) // app traffic
  8. }
  1. // API servie 接收一个service
  2. func service() {
  3. go Go(doSometing())
  4. }
  5. func doSometing() {
  6. // xxxxxx
  7. }
  8. func Go(f func()) {
  9. if err := recover(); err != nil {
  10. fmt.Println(err)
  11. }
  12. f()
  13. }

Example

  • 异步执行某个东西 ```go func main() { go Go(test) select {} }

func test() { // xxxx xxxx xxxx }

func Go(f func()) { if err := recover(); err != nil { fmt.Println(err) } f() }

  1. - 启动一个http服务
  2. ```go
  3. func main() {
  4. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  5. fmt.Fprintln(w, "Hello, GopherCon SG")
  6. })
  7. if err := http.ListenAndServe(":8080", nil); err != nil {
  8. log.Fatal(err)
  9. }
  10. }
  • 同时启动2个http监听2个端口 ```go func main() { stop := make(chan struct{}) errs := make(chan error) stoped := false // 启动server1 go func() { // Rule.3 go 由调用者发起

    1. errs <- server(":10000", stop)

    }() // 启动server2 go func() {

    1. errs <- server(":10001", stop)

    }()

    for i := 0; i < cap(errs); i++ {

    1. if err := <-errs; err != nil {
    2. fmt.Printf("err:%s", err)
    3. }
    4. if !stopped {
    5. stopped = true
    6. close(stop) // Rule.2 明确goroutine怎么退出
    7. }

    } }

func server(addr string, stop <-chan struct{}) error { s := http.Server{Addr: addr} // 监听退出信号 // Rule.1 明确goroutine什么时候退出;close关闭时 go func() { <-stop s.ShutDown(context.Background()) // Rule.2 明确server作为异步出去的goroutine怎么退出 }() return s.ListenAndServe() }

  1. - 发送异步更新数据
  2. ```go
  3. func main() {
  4. logCh := make(chan string, 10)
  5. go subLog(logCh)
  6. for i := 0; i < 1000; i++ {
  7. pub(logCh)
  8. }
  9. time.Sleep(10 * time.Second)
  10. close(logCh)
  11. }
  12. func pub(ch chan<- string) {
  13. i := strconv.Itoa(rand.Intn(10000))
  14. ch <- i
  15. }
  16. func subLog(ch <-chan string) {
  17. for s := range ch {
  18. fmt.Println("log:", s)
  19. }
  20. }