主要功能:
控制逾時時間
儲存上下文資料
基本文法結構
這裡用了底層的request來發送GET請求。&http.Client{} 的結構體裡本身也有 Timeout 的設定,預設的0值就是不設定逾時。并且Clinet要求它的 Transport 必須實作 CancelRequest 方法,預設的 Transport 是有這個方法的。是以下面的示例就是把底層的邏輯模拟了一遍,逾時後手動調用 Transport 的 CancelRequest 方法:
指令行接收第一個參數作為請求的伺服器位址,執行結果:
一次請求逾時,一次有傳回結果。
使用 context 還可以做一些自定的參數傳遞。以key-value的形式存儲到 context 的變量中,用的時候再取出來。
下面的例子試了 context 來傳遞變量:
這裡隻是示範用法,例子裡的這類明确的變量,還是應該以傳統的方式來傳遞的。那些全局需要用到的變量,可以使用 context 來進行維護。因為用了 context 之後,就把變量的資訊給隐藏了,代碼的可讀性會變差。而且隐藏了變量的類型,也不符合go的習慣,是以上面在用之前,都在了類型斷言。
通過 context.WithCancel 方法,還可以控制goroutine的生命周期:
這裡定義了2個變量,ctx和cancel。cancel是一個可以調用的函數,調用執行後。ctx.Done這個管道就能取出一個值了。在goroutine裡就可以通過這個管道來控制退出goroutine。完整示例如下:
上面這個示例的應用場景就是:當你要啟用一個goroutine執行任務,并且還需要通知這個goroutine結束的時候,就可以通過這裡的 context 來實作。
WithDeadline 和 WithTimeout 是相似的。都是通過設定,會在某個時間自動觸發,就是ctx.Done()能夠取到值。差别是,DeadLine是設定一個時間點,時間對上了就到期。Timeout是設定一段時間,比如幾秒,過個這段時間,就逾時。其實底層的Timeout也是通過Deadlin實作的,在Timeout裡,直接 return WithDeadline(parent, time.Now().Add(timeout))。
下面的例子設定了50毫秒逾時,通過WithDeadline設定。運作程式接收一個指令行參數,傳入一個整數,進過這段毫秒的時間後,會輸出自定義的内容。如果數字大了(大于50),就會逾時,這裡會輸出context的Err方法傳回的資訊:
這個例子還是使用Timeout更友善,不過這裡主要示範Deadline的用法。兩個方法的效果一樣,根據實際請求選擇合适的方法。TImeout應該更好用,是以才會對Deadine再封裝一層,提供一個Timeout方法來給更多的應用場景使用。
之前都是通過管道來和goroutine傳遞資料的,也能通過管道實作等待。不過如果隻是等待goroutine執行完畢,現在還有個方法可以實作。
通過使用 sync.WaitGroup ,可以友善的等待一組goroutine結束,具體就是下面的3步:
使用Add方法設定等待的數量,計數加1
使用Done方法設定等待數量,計數減1
當等待數量等于0時,Wait方法傳回
下面是一個發 http 請求的示例,等待所有請求傳回後,才會退出主函數:
下面的例子,展示另外一種風格的寫法:
注意:Add方法不能放在goroutine裡面。看似沒問題,不過有可能還沒等goroutine運作起來,主函數就運作到Wait了。效果就是計數還沒開始也就是0,主函數就可以繼續執行下去了。是主函數先執行Wait還是goroutine先執行到Add就看運氣了
相比管道用起來更友善也更好了解一些,而且可以等待一組goroutine。這個方法隻能實作主函數等待goroutine執行結束。如果需要通知某個goroutine退出,還是要用管道來實作。管道可以用來互動資料,是以所有的情況都适用。而 sync.WaitGroup 場景比較單一,但是更好用。