Hike News
Hike News

Go初識-day1-語言特性(高併發與channel的演示)

特性

  • 是現今雲計算時代的C語言
  • 可直接編譯不依賴其他的庫(library)
  • 為靜態語言,執行效率高

垃圾回收

C/C++因為給予程序員較自由的內存管理權限,但申請內存空間要是忘記釋放會造成內存洩漏導致記憶體滿載

  • Golang中有完整的GC機制,可以完整且快速掃描當前程序不需要使用的 對象 或 變量 並回收內存使用再也不需要開發人員主動去管理內存
  • 開發人員可專注業務實現,降低負擔
  • 只需使用new方法 分配內存,完全不用擔心釋放問題

天然併發 (Golang就是多核時代下全新的併發性語言)

  • 從語言層面支持併發,非常簡單
  • goroutine屬於輕量級線程,創建上萬個線程成為可能
  • 基於CSP (Communicating Sequential Process;通信序列進程)模型實現 —> goroutine + channel
    • 每個goroutine之間是透過channel(管道)進行通信
    • 每個goroutine都是一個可獨立執行且可調度的執行單位

學習資料

簡單goroutine範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"time"
)

func printnum(a int){
fmt.Println(a)
}

func main(){
for i:=0;i<10;i++ {
go printnum(i) //[1]
}
time.Sleep(time.Second) //[2]
}

[1] 使用關鍵字go即可調用goroutine達到併發的效果
[2] sleep用意在於 main本身也是一個進程,在創建線程的過程中並不會理會其他子線程的執行狀況仍會繼續往下執行,可能會造成主進程執行完畢,但子進程仍還在執行而導致結果不符合預期,故目的是為了等待子線程也都執行完畢,主線程才繼續執行

result

1
2
3
4
5
6
7
8
9
10
1
0
3
4
2
6
5
7
8
9

可以看到輸出為無序的打印0-9所有數字,表示線程之間可單獨調度執行,證明為併發執行
如果不為併發執行應該是有序的0-9

管道(channel)

  • 管道,類似unix/linux中的pipe 或是 |
    • 進程之間的資源是隔離且彼此獨立,因此想實現通訊處理,就必須透過管道來實現
    • 所有進程都能訪問管道,因此A進程可將數據放入管道中,由B進程提取實現通信
  • 多個goroutine之間通過channel進行通信
  • 支持任何類型
  • 數據先進先出

channel

簡單管道範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import "fmt"

func pipe_test(){
pipe := make(chan int,3) //[1]
pipe <- 1 //[2]
pipe <- 2
pipe <- 3

var t int
t =<- pipe //[3]
fmt.Println(t)

pipe <- 4 //[4]
}

[1] 分配一個內存空間用於創建(make)管道(chan),管道容量為3,為int類型

等同於

1
2
var pipe chan int
pipe = make(chan int,3)

  • 管道內只能放3個int類型的數據
  • 存放的數據超過容量值會阻塞,並等待消耗後存入數據
  • 如在編譯時檢測到有阻塞且無法解決,會拋出deadlock錯誤

[2] 透過 <- 將右邊的數據存放至管道中

[3] 透過 =<- 從右邊的管道取值賦給左邊的變量

[4] 管道pipe空出一個位置,可允許數值在繼續存入

result

1
1

多返回值

一個函數可以返回多個值

簡單多返回值範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func calc (a,b int)(int,int){ //[1]
sum := a+b
avg := (a+b)/2
return sum,avg //[1]
}

func main(){
sum,avg := calc(10,20) //[2]
fmt.Println("sum of a and b =", sum)
fmt.Println("avg of a and b =", avg)
}

[1] 返回多個值可在參數後面使用(返回值1的類型,返回值2的類型)來獲取多個返回值,return多個返回值之間用,隔開
[2] 使用多個變量來接收多個返回值

result

1
2
sum of a and b = 30
avg of a and b = 15

將用不到的返回值忽略

在上一章提到在Go中定義的變量名在腳本中沒有被使用,編譯時會報錯,必須刪除其變量,才能正常編譯
但是函數又有多個返回值該怎辦?
可用_ (下劃線) 忽略掉
以上述代碼為例,要是用不到avg值則代碼改寫如下

1
2
3
4
func main(){
sum,_ := calc(10,20) //[2]
fmt.Println("sum of a and b =", sum)
}

可成功編譯不會報錯

1
sum of a and b = 30