context
一般来说,goroutine是平级关系,但是通过引进context可以让其有逻辑上的父子关系
也就是,父要子停,子不得不停的意思
揣摩一下哈

手动cancel

package main

import (
	"context"
	"fmt"
	"time"
)

func HandelRequest(ctx context.Context) {
	go WriteLog(ctx)
	go WriteDB(ctx)
	for {
		select {
		case <-ctx.Done():
			fmt.Println("请求处理完毕")
			return
		default:
			fmt.Println("请求处理中……")
			time.Sleep(2 * time.Second)
		}
	}
}
func WriteLog(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("写日志完成")
			return
		default:
			fmt.Println("写日志中……")
			time.Sleep(2 * time.Second)
		}
	}
}
func WriteDB(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("写数据库完成")
			return
		default:
			fmt.Println("写数据库中……")
			time.Sleep(2 * time.Second)
		}
	}
}
func main() {
	//WithCancel
	ctx, cancel := context.WithCancel(context.Background())
	go HandelRequest(ctx)
	time.Sleep(5 * time.Second)
	fmt.Println("所有子协程都需要结束!")
	cancel()
	//Just for test whether sub goroutines exit or not
	time.Sleep(5 * time.Second) 

	//WithTimeout
	/*ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
	go HandelRequest(ctx)
	time.Sleep(10 * time.Second)*/

}

分析:
1.ctx, cancel := context.WithCancel(context.Background())通过ctx记录上下文,和cancel用来进行删除
2.当且仅当启动了cancel才会触发<-ctx.Done(),然后三个子协程全部停止

结果:

自动timeout

package main

import (
	"context"
	"fmt"
	"time"
)

func HandelRequest(ctx context.Context) {
	go WriteLog(ctx)
	go WriteDB(ctx)
	for {
		select {
		case <-ctx.Done():
			fmt.Println("请求处理完毕")
			return
		default:
			fmt.Println("请求处理中……")
			time.Sleep(2 * time.Second)
		}
	}
}
func WriteLog(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("写日志完成")
			return
		default:
			fmt.Println("写日志中……")
			time.Sleep(2 * time.Second)
		}
	}
}
func WriteDB(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("写数据库完成")
			return
		default:
			fmt.Println("写数据库中……")
			time.Sleep(2 * time.Second)
		}
	}
}
func main() {
	//WithCancel
	/*
	ctx, cancel := context.WithCancel(context.Background())
	go HandelRequest(ctx)
	time.Sleep(5 * time.Second)
	fmt.Println("所有子协程都需要结束!")
	cancel()
	//Just for test whether sub goroutines exit or not
	time.Sleep(5 * time.Second)*/

	//WithTimeout
	ctx, _ := context.WithTimeout(context.Background(), 7*time.Second)
	go HandelRequest(ctx)
	time.Sleep(10 * time.Second)

}

分析:
1.这里改成7秒,足够写出4次工作中了(分别是0,2,4,6)
2.然后7秒该ctx下全部done完,结束工作

结果: