最近在使用golang做一個爬蟲,涉及到多線程,golang是沒有多線程的,但是有一種更輕量級能達到類似多線程的效果,協程,golang原生支持協程。
一、怎麼理解協程?
協程是golang語言特性的實現,比線程更低一級的運行方式,它不屬於操作系統功能,不由操作系統分配cpu、內存,而是由golang自己實現運行資源的調度使用。也正是因此執行效率要高於線程。但是協程需要主動讓出控制權後供其他協程運行。
二、如何創建協程?
這裏有2種方式創建:
1、使用go創建
go sf("a")
2、使用go函數塊創建
go func() {
sf("b")
}()
三、使用協程的問題
1、主線程執行完成後直接結束了,此時若協程未執行完成,也會直接結束,毫無徵兆。
下面是個例子
func main() {
fmt.Println("開始啓動...")
go sf("a")
go sf("b")
}
func sf(s string) {
for i := 0; i < 10; i++ {
fmt.Println(s+" ->>>", i)
}
}
運行完成之後根本不會等兩個協程完成運行,主函數直接結束了,如果將代碼改一下
改版1:
func main() {
fmt.Println("開始啓動...")
go sf("a")
go sf("b")
time.Sleep(time.Duration(2)*time.Minute)
}
在主函數這裏阻塞一下,就可以了,但是這種方式在實際開發中是不可行的,大多不能提前知道協程需要多久運行完成。
改版2:
func main() {
fmt.Println("開始啓動...")
var wg = sync.WaitGroup{}
wg.Add(2)
go func() {
sf("a")
wg.Done()
}()
go func() {
sf("b")
wg.Done()
}()
wg.Wait()
}
這樣運行就ok了,這裏使用了golang的WaitGroup。
理解起來就是創建一個等待的組,可以動態的添加組員的數量,然後在主函數最後一行執行wg.Wait() 來阻塞檢查組員是否都完成了,協程中調用wg.Done()方法進行減一操作告知當前協程完成。
這樣也會帶來新的問題:
1、無法精確控制協程
2、無法準確得知哪個協程完成了或未完成
3、代碼過於原始(繁瑣)
拿java的多線程來理解,這個WaitGroup就像一個線程池,但是池子裏只有計數器,沒有實際對象。在Wait()方法一直在等待WaitGroup的校驗信號,當一個協程完成時使用Done()通知WaitGroup已完成,當所有協程全部通知完成了Wait()釋放,這就是一個非常簡單的消息模型。
在協程這塊,希望golang能優化使用方式,儘可能優雅一些。
找到了一篇講的挺到位的文章,手動傳送門 https://www.cnblogs.com/liang1101/p/7285955.html