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

相關文章
相關標籤/搜索