C語言中文網 目錄
首頁 > Go語言教程 > Go語言簡介 閱讀:12,601

Go語言為并發而生

現今,多核 CPU 已經成為服務器的標配,但是對多核的運算能力挖掘一直由程序員人工設計算法及框架來完成,這個過程需要開發人員具有一定的并發設計及框架設計能力。

雖然一些編程語言的框架在不斷地提高多核資源使用效率,例如 Java 的 Netty 等,但仍然需要開發人員花費大量的時間和精力搞懂這些框架的運行原理后才能熟練掌握。

Go 語言在多核并發上擁有原生的設計優勢。Go 語言從 2009 年 11 月開源,2012 年發布 Go 1.0 穩定版本以來,已經擁有活躍的社區和全球眾多開發者,并且與蘋果公司的 Swift 一樣,成為當前非常流行的開發語言之一。

很多公司,特別是中國的互聯網公司,即將或者已經完成了使用 Go 語言改造舊系統的過程。經過 Go 語言重構的系統能使用更少的硬件資源而有更高的并發和 I/O 吞吐表現。

Go語言從底層原生支持并發,無須第三方庫、開發者的編程技巧和開發經驗就可以輕松地在 Go 語言運行時來幫助開發者決定怎么使用 CPU 資源。

Go語言的并發是基于 goroutine 的,goroutine 類似于線程,但并非線程。可以將 goroutine 理解為一種虛擬線程。Go 語言運行時會參與調度 goroutine,并將 goroutine 合理地分配到每個 CPU 中,最大限度地使用CPU性能。

多個 goroutine 中,Go 語言使用通道(channel)進行通信,程序可以將需要并發的環節設計為生產者模式和消費者的模式,將數據放入通道。通道的另外一端的代碼將這些數據進行并發計算并返回結果,如下圖所示。


下面代碼中的生產者每秒生成一個字符串,并通過通道傳給消費者,生產者使用兩個 goroutine 并發運行,消費者在 main() 函數的 goroutine 中進行處理。
package main

import (
        "fmt"
        "math/rand"
        "time"
)

// 數據生產者
func producer(header string, channel chan<- string) {
     // 無限循環, 不停地生產數據
     for {
            // 將隨機數和字符串格式化為字符串發送給通道
            channel <- fmt.Sprintf("%s: %v", header, rand.Int31())
            // 等待1秒
            time.Sleep(time.Second)
        }
}

// 數據消費者
func customer(channel <-chan string) {
     // 不停地獲取數據
     for {
            // 從通道中取出數據, 此處會阻塞直到信道中返回數據
            message := <-channel
            // 打印數據
            fmt.Println(message)
        }
}

func main() {
    // 創建一個字符串類型的通道
    channel := make(chan string)
    // 創建producer()函數的并發goroutine
    go producer("cat", channel)
    go producer("dog", channel)
    // 數據消費函數
    customer(channel)
}
運行結果:
dog: 2019727887
cat: 1298498081
dog: 939984059
cat: 1427131847
cat: 911902081
dog: 1474941318
dog: 140954425
cat: 336122540
cat: 208240456
dog: 646203300

對代碼的分析:
  • 第03行,導入格式化(fmt)、隨機數(math/rand)、時間(time)包參與編譯。
  • 第10行,生產數據的函數,傳入一個標記類型的字符串及一個只能寫入的通道。
  • 第13行,for{}構成一個無限循環。
  • 第15行,使用rand.Int31()生成一個隨機數,使用fmt.Sprintf()函數將header和隨機數格式化為字符串。
  • 第18行,使用time.Sleep()函數暫停1秒再執行這個函數。如果在goroutine中執行時,暫停不會影響其他goroutine的執行。
  • 第23行,消費數據的函數,傳入一個只能寫入的通道。
  • 第26行,構造一個不斷消費消息的循環。
  • 第28行,從通道中取出數據。
  • 第31行,將取出的數據進行打印。
  • 第35行,程序的入口函數,總是在程序開始時執行。
  • 第37行,實例化一個字符串類型的通道。
  • 第39行和第40行,并發執行一個生產者函數,兩行分別創建了這個函數搭配不同參數的兩個goroutine。
  • 第42行,執行消費者函數通過通道進行數據消費。

整段代碼中,沒有線程創建,沒有線程池也沒有加鎖,僅僅通過關鍵字 go 實現 goroutine,和通道實現數據交換。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo