1. 程式人生 > 其它 >每日一抄 Go語言等待組

每日一抄 Go語言等待組

package main

import (
	"fmt"
	"net/http"
	"sync"
)

/*
Go語言除了可以使用通道(channel)和互斥鎖進行兩個併發程式間的同步外,還可以使用等待組進行多個任務的同步
,等待組可以保證在併發環境中完成指定數量的任務

在sync.WaitGroup(等待組)型別中,每個sync.WaitGroup值在內部維護著一個計數,此計數的初始預設值為零
等待組有下面幾個方法可用:
(wg *WaitGroup) Add(delta int)// 等待組的計數器加一
(wg *WaitGroup) Done() //等待組的計數器減一
(wg *WaitGroup) Wait() //當等待組計數器不等於0時阻塞,直到變0


對於一個可定址的sync.WaitGroup值wg:
1.我們可以使用方法呼叫呼叫wg.Add(delta)來改變值wg維護的計數
2.方法呼叫wg.Done()和wg.Add(-1)是完全等價的
3.如果一個wg.Add(delta)或者wg.Done()呼叫將wg維護的計數更改為一個負數,一個恐慌將產生
4.當一個協程呼叫了wg.Wait()時,
	如果此時wg維護的計數為零,則此wg.Wait()操作為一個空操作(noop)
	否則(計數為一個正整數),則此協程將進入阻塞狀態。當以後其他某個協程將此計數更改至零時(一般通過呼叫wg.Done()),
此協程將重新進入執行狀態(即 wg.Wait()將返回)。

等待組內部擁有一個計數器,計數器的值可以通過方法呼叫實現計數器的增加和減少。當我們添加了 N 個併發任務進行工作時,就將等待組的計數器值增加 N。每個任務完成時,這個值減 1。
同時,在另外一個 goroutine 中等待這個等待組的計數器值為 0 時,表示所有任務已經完成。
*/

func main() {
	//宣告一個等待組
	var wg sync.WaitGroup
	//準備一系列的網站地址
	//字串切片
	var urls = []string{
		"http://www.github.com/",
		"https://www.qiniu.com/",
		"https://www.golangtc.com/",
	}
	//遍歷這些地址
	for _, url := range urls {
		//每個任務開始時,將等待組增加
		wg.Add(1)
		//開啟一個併發
		//這裡將 url 通過 goroutine 的引數進行傳遞,是為了避免 url 變數通過閉包放入匿名函式後又被修改的問題。
		go func(url string) {
			//使用defer,表示函式完成是將等待組的值減一
			defer wg.Done()
			//使用http訪問提供的地址
			//使用 http 包提供的 Get() 函式對 url 進行訪問,Get() 函式會一直阻塞直到網站響應或者超時。
			_, err := http.Get(url)
			//訪問完成後,列印地址可能發生的錯誤
			if err != nil {
				fmt.Println(url, err)
			}
			fmt.Println("fangwen", url)
		}(url)
	}

	//等待所有任務完成
	wg.Wait()
	fmt.Println("over")
}