Go 多个goroutine间协作和传递信息
网络请求Request 需要 goroutine访问后端资源 数据库 RPC服务等 这些goroutine又开启其他的goroutine 如何跟踪和控制这些goroutine
context在多个API和进程之间 实现deadlines截止日期操作 cancelation signals 取消操作 及传递request-scoped 值(即传递参数)
context最大的特点是可以继承 父context 派生子context 子context 又可派生子context 如果父context被取消 子context及其子context都被取消
context 派生方法
有 WithCancel WithDeadline WithTimeout WithValue 其中 WithCancel 主动取消自身以及子context
WithDeadline 和WithTimeout用于超时情况下的取消自身以及子context。WithTimeout实现上直接调用WithDeadline
WithValue用于context传递request-scoped的参数 而不是向函数传递的可选参数
演示控制多个goroutine退出
启动2个goroutine 分别命名为 one two 每个goroutine又启动一个goroutine 就是有4个goroutine
main 调用取消操作cancel 先是one two 收到信号退出
one two  退出的时候又调用它们的cancel 这样所有的goroutine都被取消并退出
package main
import (
        "context"
        "fmt"
        "time"
)
func PrintTask(ctx context.Context, taskName string) {
    for {
        select {
        case <- ctx.Done():
                fmt.Println("task:", taskName, " exit...")
                return
        default:
                time.Sleep(1*time.Second)
                fmt.Println("task:", taskName, "PrintTask doing something...")
        }
    }
}
func MainTask(ctx context.Context, taskName string) {
    ctx1, cancel := context.WithCancel(ctx)
    defer cancel()        
    newTaskName := taskName + "1"
    go PrintTask(ctx1, newTaskName)// create a new task
    for {
        select {
        case <- ctx.Done():
            fmt.Println("task:", taskName, " exit...")
            return
        default:
            time.Sleep(1*time.Second)
            fmt.Println("task:", taskName, "MainTask doing something...")
        }
    }
}

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    go MainTask(ctx, "one")
    go MainTask(ctx, "two")
    time.Sleep(3*time.Second)
    cancel()
    fmt.Println("main cancel ...")
    time.Sleep(3*time.Second)
}//output
task: one MainTask doing something...
task: one1 PrintTask doing something...
task: two MainTask doing something...
task: two1 PrintTask doing something...
task: one1 PrintTask doing something...
task: two MainTask doing something...
task: one MainTask doing something...
task: two1 PrintTask doing something...
main exit...
task: two MainTask doing something...
task: two  exit...
task: one1 PrintTask doing something...
task: one1  exit...
task: two1 PrintTask doing something...
task: two1  exit...
task: one MainTask doing something...
task: one  exit...