淺談go之介面、執行緒、通道,純屬個人看法
淺談go介面、通道、執行緒
golang 接 口
Go 是靜態型別的。每一個變數有一個靜態的型別,也就是說,有一個已知型別並且在編譯時就確定下來了
type MyInt int
var i int
var j MyInt
那麼 i 的型別為 int 而 j 的型別為 MyInt。即使變數 i 和 j 有相同的底層型別,它們仍然是有不同的靜態型別的。未經轉換是不能相互賦值的。
interface
interface是一組method簽名的組合,我們通過interface來定義物件的一組行為。
interface型別定義了一組方法,如果某個物件實現了某個介面的所有方法,則此物件就實現了此介面。
注:介面實際可以理解為幾種方法的集合,呼叫介面的時候可以與呼叫結構體中的方法的時候一樣,用物件 . 方法 來呼叫。
goroutine併發程式設計
goroutine是通過Go的runtime管理的一個執行緒管理器。goroutine通過go關鍵字實現了,其實就是一個普通的函式。
通過關鍵字go就啟動了一個goroutine。我們來看一個例子
package main
import (
“fmt”
“runtime”
)
func say(s string) {
for i := 0; i < 2; i++ {
//runtime.Gosched()
fmt.Println(s)
runtime.Gosched()
}
}
func main() {
go say(“world”) //開一個新的Goroutines執行
say(“hello”) //當前Goroutines執行
}
執行結果:
hello
world
hello
world
稍微改動一下程式碼
package main
import (
“fmt”
“runtime”
)
func say(s string) {
for i := 0; i < 2; i++ {
//runtime.Gosched()
fmt.Println(s)
runtime.Gosched()
}
}
func main() {
go say(“world”) //開一個新的Goroutines執行
say(“hello”) //當前Goroutines執行
}
執行結果如下
hello
world
hello
我們可以看到go關鍵字很方便的就實現了併發程式設計。 上面的多個goroutine執行在同一個程序裡面,共享記憶體資料,不過設計上我們要遵循:不要通過共享來通訊,而要通過通訊來共享。
runtime.Gosched()表示讓CPU把時間片讓給別人,下次某個時候繼續恢復執行該goroutine。
channel
通道(Channel)可以被認為是協程之間通訊的管道。資料可以從通道的一端傳送並在另一端接收。
1.宣告通道:
每個通道都有一個與之關聯的型別。此型別是允許通道傳輸的資料型別,除此型別外不能通過通道傳輸其他型別。
chan T 是一個T型別的通道
通道的0值為nil。值為nil的通道變數沒有任何用處,我們需要通過內建函式make來建立一個通道,就像建立map 和 slice一樣。
a := make(chan int) 定義了一個int型的通道。
2.通過通道傳送和接受資料
data :=<-a //read from channel a
a<- data //write to channel
箭頭的指向說明了資料是傳送還是接收
在第一行,箭頭的方向是從a向外指,因此我們正在從通道a中讀取資料並將讀取的值賦值給變數data。
在第二行,箭頭的方向是指向a,因此我們正在向通道a中寫入資料。
3.傳送和接收預設是阻塞的
當資料傳送給通道後,程式流程在傳送語句處阻塞,直到其他協程從該通道中讀取資料。同樣地,當從通道讀取資料時,程式在讀取語句處阻塞,直到其他協程傳送資料給該通道。
通道使得協程間通訊變得高效。
舉例1
package main
import “fmt”
func sum(a []int, c chan int) {
total := 0
for _, v := range a {
total += v
}
c <- total // send total to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[:len(a)/2], c) //17
go sum(a[len(a)/2:], c) //-5
go sum(a[:len(a)], c) //12
x, y, z := <-c, <-c, <-c // receive from c
//x := <-c
fmt.Println(x)
fmt.Println(y)
fmt.Println(z)
fmt.Println(x, y, z, x+y)
}
輸出結果:
12
17
-5
12 17 -5 29
舉例2:
package main
import “fmt”
func main() {
c := make(chan int, 2)//修改2為1就報錯,修改2為3可以正常執行
c <- 1
c <- 2
fmt.Println(<-c)
fmt.Println(<-c)
}
//修改為1報如下的錯誤:
//fatal error: all goroutines are asleep - deadlock!
純粹是連菜鳥都算不上,只是寫寫自己的理解,如果有錯,請大家指正,萬分感謝!!!