91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go語言之goroutine

發布時間:2020-07-11 07:09:41 來源:網絡 閱讀:277 作者:baby神 欄目:編程語言

在談goroutine之前,我們先談談并發和并行。


一般的程序,如果沒有特別要求的話,是順序執行的,這樣的程序也容易編寫維護。但是隨著科技的發展、業務的演進,我們不得不變寫可以并行的程序,因為這樣有很多好處。


比如你在看文章的時候,還可以聽著音樂,這就是系統的并行,同時可以做多件事情,充分地利用計算機的多核,提升軟件運行的性能。


在操作系統中,有兩個重要的概念:一個是進程、一個是線程。當我們運行一個程序的時候,比如你的IDE或者QQ等,操作系統會為這個程序創建一個進程,這個進程包含了運行這個程序所需的各種資源,可以說它是一個容器,是屬于這個程序的工作空間,比如它里面有內存空間、文件句柄、設備和線程等。


那么線程是什么呢?線程是一個執行的空間,比如要下載一個文件,訪問一次網絡等。線程會被操作系統調用,來在不同的處理器上運行編寫的代碼任務,這個處理器不一定是該程序進程所在的處理。操作系統的調度是操作系統負責的,不同的操作系統可能會不一樣,但是對于我們程序編寫者來說,不用關心,因為對我們都是透明的。


一個進程在啟動的時候,會創建一個主線程,這個主線程結束的時候,程序進程也就終止了,所以一個進程至少有一個線程。這也是我們在main函數里,使用goroutine的時候,要讓主線程等待的原因,因為主線程結束了,程序就終止了,那么就有可能會看不到goroutine的輸出。


Go語言中并發指的是讓某個函數獨立于其他函數運行的能力,一個goroutine就是一個獨立的工作單元,Go的runtime(運行時)會在邏輯處理器上調度這些goroutine來運行,一個邏輯處理器綁定一個操作系統線程,所以說goroutine不是線程,它是一個協程,也是這個原因,它是由Go語言運行時本身的算法實現的。


這里我們總結下幾個概念:


概念

說明

進程

一個程序對應一個獨立程序空間

線程

一個執行空間,一個進程可以有多個線程

邏輯處理器

執行創建的goroutine,綁定一個線程

調度器

Go運行時中的,分配goroutine給不同的邏輯處理器

全局運行隊列

所有剛創建的goroutine都會放到這里

本地運行隊列

邏輯處理器的goroutine隊列


當我們創建一個goroutine后,會先存放在全局運行隊列中,等待Go運行時的調度器進行調度。把他們分配給其中的一個邏輯處理器,并放到這個邏輯處理器對應的本地運行隊列中,最終等著被邏輯處理器執行即可。


這一套管理、調度、執行goroutine的方式稱之為Go的并發。并發可以同時做很多事情,比如有個goroutine執行了一半,就被暫停執行其他goroutine去了,這是Go控制管理的。所以并發的概念和并行不一樣,并行指的是在不同的物理處理器上同時執行不同的代碼片段,并行可以同時做很多事情;并發是同時管理很多事情,因為操作系統和硬件的總資源比較少,所以并發的效果要比并行好的多,使用較少的資源做更多的事情,也是Go語言提倡的。


Go的并發原理我們剛剛講了,那么Go的并行是怎樣的呢?其實答案非常簡單,多創建一個邏輯處理器就好了,這樣調度器就可以同時分配全局運行隊列中的goroutine到不同的邏輯處理器上并行執行。


func main() {
    var wg sync.WaitGroup
    wg.Add(2)
    go func(){
        defer wg.Done()
        for i:=1;i<100;i++ {
            fmt.Println("A:",i)
        }
    }()
    go func(){
        defer wg.Done()
        for i:=1;i<100;i++ {
            fmt.Println("B:",i)
        }
    }()
    wg.Wait()
}


這是一個簡單的并發程序。創建一個goroutine是通過go關鍵字的,其后跟一個函數或者方法即可。


這里的sync.WaitGroup其實是一個計數的信號量,使用它的目的是要main函數等待兩個goroutine執行完成后再結束,不然這兩個goroutine還在運行的時候,程序就結束了,看不到想要的結果。


sync.WaitGroup的使用也非常簡單,先是使用Add方法設置計算器為 2 ,每一個goroutine的函數執行完之后,就調用Done方法減 1 。Wait方法的意思是如果計數器大于 0 ,就會阻塞,所以main函數會一直等待兩個goroutine完成后,再結束。


我們運行這個程序,發現A和B前綴會交叉出現,并且每次運行的結果可能不一樣,這就是Go調度器調度的結果。


默認情況下,Go默認是給每個可用的物理處理器都分配一個邏輯處理器,因為我的電腦是 4 核的,所以上面的例子默認創建了 4 個邏輯處理器,所以這個例子中同時也有并行的調度,如果我們強制只使用一個邏輯處理器,我們再看看結果。


func main() {
    runtime.GOMAXPROCS(1)
    var wg sync.WaitGroup
    wg.Add(2)
    go func(){
        defer wg.Done()
        for i:=1;i<100;i++ {
            fmt.Println("A:",i)
        }
    }()
    go func(){
        defer wg.Done()
        for i:=1;i<100;i++ {
            fmt.Println("B:",i)
        }
    }()
    wg.Wait()
}


設置邏輯處理器個數也非常簡單,在程序開頭使用runtime.GOMAXPROCS(1)即可,這里設置的數量是 1 。我們這時候再運行,會發現先打印A,再打印B。


這里我們不要誤認為是順序執行,這里之所以順序輸出的原因,是因為我們的goroutine執行時間太短暫了,還沒來得及切換到第 2 個goroutine,第 1 個goroutine就完成了。這里我們可以把每個goroutine的執行時間拉長一些,就可以看到并發的效果了,這里不再示例了,大家自己試試。


對于邏輯處理器的個數,不是越多越好,要根據電腦的實際物理核數。如果不是多核的,設置再多的邏輯處理器個數也沒用。如果需要設置的話,一般我們采用如下代碼設置。


runtime.GOMAXPROCS(runtime.NumCPU())


所以對于并發來說,就是Go語言本身自己實現的調度;對于并行來說,是和運行的電腦的物理處理器的核數有關的,多核就可以并行并發,單核只能并發了。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

东源县| 宿迁市| 岢岚县| 新龙县| 手游| 文化| 长白| 即墨市| 辽宁省| 淳化县| 宝应县| 哈密市| 额尔古纳市| 巨野县| 左云县| 宁海县| 巴中市| 嘉黎县| 开鲁县| 孙吴县| 南安市| 涟源市| 平武县| 曲松县| 鲁甸县| 洛南县| 敦煌市| 昭通市| 防城港市| 遂溪县| 宜黄县| 九台市| 深水埗区| 柯坪县| 临武县| 九江县| 榆社县| 和田市| 乐安县| 宁蒗| 安丘市|