Golang several ways to exit goroutine

The traditional way

In the beginning of the school go, never used Context package, then exit Ctrip way to have so few

Using the notification message transmitted chan carrying this general only suitable for single goroutine

func exit01() {
    done := make(chan bool)
    go func() {
        for {
            select {
            case <-done:
                fmt.Println("退出携程")
                return
            default:
                fmt.Println("监控中...")
                time.Sleep(1 * time.Second)
            }
        }
    }()
    time.Sleep(3 * time.Second)
    done <- true
    time.Sleep(5 * time.Second)
    fmt.Println("程序退出")
}

Use closed chan way to notify multiple goroutine exit

func exit02() {
    done :=make(chan bool)
    go func() {
        for{
            select {
            case <-done:
                fmt.Println("退出携程01")
                return
            default:
                fmt.Println("监控01...")
                time.Sleep(1*time.Second)
            }
        }
    }()

    go func() {
        for res :=range done{ //没有消息阻塞状态,chan关闭 for 循环结束
            fmt.Println(res)
        }
        fmt.Println("退出监控03")
    }()

    go func() {
        for{
            select {
            case <-done:
                fmt.Println("退出携程02")
                return
            default:
                fmt.Println("监控02...")
                time.Sleep(1*time.Second)
            }
        }
    }()
    time.Sleep(3*time.Second)
    close(done)
    time.Sleep(5*time.Second)
    fmt.Println("退出程序")
}

Acquaintance Context package

A manual control for the exit or end goroutine

Two ways to get context context

ctx := context.Background() //这只能用于高等级(在 main 或顶级请求处理中)。这能用于派生我们稍后谈及的其他 context

ctx := context.TODO()  // 也只能用于高等级或当您不确定使用什么 context,或函数以后会更新以便接收一个 context 

Their underlying achieve exactly the same, the difference is that static analysis tools can use it to verify context is correct pass,
this is an important detail, because the static analysis tools can help identify potential errors early, and can connect to CI / CD pipes

var (
    background = new(emptyCtx)
    todo       = new(emptyCtx)
)

Use context.WithTimeout, take the initiative to call the cancel () method, you can exit before time expires goroutine

func exit03() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    go func() {
        for{
            select {
            case <-ctx.Done():
                fmt.Println("退出携程")
                return
            default:
                fmt.Println("请求中..")
                time.Sleep(1*time.Second)
            }
        }
    }()
    time.Sleep(5*time.Second)
    //cancel() //也可以手动调用 cancel()方法退出
    //time.Sleep(2*time.Second)
    fmt.Println("程序退出")

}

Use context.WithCanel () method, according to the external conditions of manual call cancel () method to exit
only create its function can be called to cancel functions to cancel this context. If you prefer, you can cancel the transfer function, however, is strongly discouraged.
This may result in the caller did not realize cancel cancel function of downstream impacts context. There may be other context from this, and
this may cause the program to run in unexpected ways. In short, never cancel the transfer function

func exit04() {
    ctx, cancel := context.WithCancel(context.Background())
    go func() {
        for{
            select {
            case <-ctx.Done():
                fmt.Println("退出携程")
                return
            default:
                fmt.Println("监控01")
                time.Sleep(1*time.Second)
            }
        }
    }()

    time.Sleep(5*time.Second)
    cancel()
    time.Sleep(2*time.Second)
    fmt.Println("退出程序")

}   

Use context.WithDeadLine (), exit at a specified time goroutine

func exit05() {
    stringTime := "2019-08-11 09:08:01"
    loc, _ := time.LoadLocation("Local")
    the_time, _ := time.ParseInLocation("2006-01-02 15:04:05", stringTime, loc)
    ctx, _ := context.WithDeadline(context.Background(), the_time)
    go func() {
        for{
            select {
            case <-ctx.Done():
                fmt.Println("退出 goroutine")
                return
            default:
                fmt.Println("监控...")
                time.Sleep(1*time.Second)
            }
        }
    }()

    time.Sleep(60*time.Second)
    fmt.Println("程序退出")

}

Use context.WithValue () by value, can be acquired in all of the context tree to the value, if the key is set to cover the same value
does not recommend use of context parameter values passed critical, but is a function of those values to be received signature so made explicit.

func exit06() {
    ctx := context.WithValue(context.Background(), "msg", "hello word")
    go func(ctx context.Context) {
        fmt.Println(ctx.Value("msg"))
    }(ctx)
    time.Sleep(2*time.Second)
    fmt.Println("程序退出")
}

Recommendations constraints

  • context.Background applied only at the highest level, as the root of all derived context.
  • context.TODO application in uncertain where what you want to use, or after the current function will be updated to use context.
  • Cancel suggestive context, these functions may take some time to clean up and exit.
  • context.Value should be rarely used, it should not be used to pass optional parameters. This API makes the implicit and can cause errors. Instead, these values ​​should be passed as a parameter.
  • Do not stored in the context structure, function transfer them explicitly, preferably as the first parameter.
  • Never passed context does not exist. Conversely, if you are not sure what to use, use a ToDo context.
  • Context structure no cancellation method, since only a derived function should be canceled before the context of context.

Reference: https://studygolang.com/articles/13866?fr=sidebar

Guess you like

Origin www.cnblogs.com/nirao/p/11333990.html