go context包的WithTimeout和WithCancel的使用

一、WaitGroup安全

  它是一种控制并发的方式,它的这种方式是控制多个goroutine同时完成。多线程

func main() {
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		time.Sleep(2*time.Second)
		fmt.Println("1号完成")
		wg.Done()
	}()
	go func() {
		time.Sleep(2*time.Second)
		fmt.Println("2号完成")
		wg.Done()
	}()
	wg.Wait()
	fmt.Println("好了,你们都干完了,放工")
}

  一个很简单的例子,必定要例子中的2个goroutine同时作完,才算是完成,先作好的就要等着其余未完成的,全部的goroutine要都所有完成才能够。并发

二、chan通知函数

  咱们都知道一个goroutine启动后,咱们是没法控制他的,大部分状况是等待它本身结束,那么若是这个goroutine是一个不会本身结束的后台goroutine呢?好比监控等,会一直运行的。线程

  这种状况化,一直傻瓜式的办法是全局变量,其余地方经过修改这个变量完成结束通知,而后后台goroutine不停的检查这个变量,若是发现被通知关闭了,就自我结束。协程

  这种方式也能够,可是首先咱们要保证这个变量在多线程下的安全,基于此,有一种更好的方式:chan + select 。blog

func main() {
	stop := make(chan bool)
	go func() {
		for {
			select {
			case <-stop:
				fmt.Println("监控退出,中止了...")
				return
			default:
				fmt.Println("goroutine监控中...")
				time.Sleep(2 * time.Second)
			}
		}
	}()
	time.Sleep(10 * time.Second)
	fmt.Println("能够了,通知监控中止")
	stop<- true
	//为了检测监控过是否中止,若是没有监控输出,就表示中止了
	time.Sleep(5 * time.Second)
}

  

三、WithTimeout 超时自动取消方法接口

   当执行一个go 协程时,超时自动取消协程it

// 模拟一个最小执行时间的阻塞函数
func inc(a int) int {
	res := a + 1                // 虽然我只作了一次简单的 +1 的运算,
	time.Sleep(1 * time.Second) // 可是因为个人机器指令集中没有这条指令,
	// 因此在我执行了 1000000000 条机器指令, 续了 1s 以后, 我才终于获得结果。B)
	return res
}

// 向外部提供的阻塞接口
// 计算 a + b, 注意 a, b 均不能为负
// 若是计算被中断, 则返回 -1
func Add(ctx context.Context, a, b int) int {
	res := 0
	for i := 0; i < a; i++ {
		res = inc(res)
		select {
		case <-ctx.Done():
			return -1
		default:
		}
	}
	for i := 0; i < b; i++ {
		res = inc(res)
		select {
		case <-ctx.Done():
			return -1
		default:
		}
	}
	return res
}

  计算 a+bclass

func main() {
	// 使用开放的 API 计算 a+b
	a := 1
	b := 2
	timeout := 2 * time.Second
	ctx, _ := context.WithTimeout(context.Background(), timeout)
	res := Add(ctx, 1, 2)
	fmt.Printf("Compute: %d+%d, result: %d\n", a, b, res)
}

  输出结果:Compute: 1+2, result: -1

四、WithCancel 手动取消方法
func main() {
	// 手动取消
	a := 1
	b := 2
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		time.Sleep(2 * time.Second)
		cancel() // 在调用处主动取消
	}()
	res := Add(ctx, 1, 2)
	fmt.Printf("Compute: %d+%d, result: %d\n", a, b, res)
}

  输出结果:Compute: 1+2, result: -1

相关文章
相关标签/搜索