並行與併發
併發:一個時間段內有很多的線程或進程在執行,但何時間點上都只有一個在執行,多個線程或進程爭搶時間片輪流執行,多線程模型
並行:一個時間段和時間點上都有多個線程或進程在執行,需要多個核心處理器(CPU)
Go 併發
Go 語言併發,通過 go 關鍵字來開啓 goroutine ,goroutine 是輕量級線程,goroutine 的調度是由 Golang 運行時進行管理的。
goroutine 語法格式:
go 函數名( 參數列表 )
例如:
go fast(x, y, z) //開啓一個新的 goroutine
同一個程序中的所有 goroutine 共享同一個地址空間
package main
import (
"fmt"
)
func printfString(s string) {
for i := 0; i < 2; i++ {
//time.Sleep(1 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go printfString("3333")
go printfString("4444")
go printfString("1111")
printfString("2222")
}
- 併發執行,執行的順序不確定
- main 函數執行完成後退出後,可能協程還未退出
- 一個內核線程對應用戶態多個goroutine,goroutine和OS線程是多對多的關係。
通道(channel)
-定義:通道(channel)是用來傳遞數據的一個數據結構。一個 channel是一個通信機制,每個 channel 都有類型(發送/接受數據的類型)。列如:發送 int 類型數據的 channel : chan int。
- 創建:
ch := make(chan int) - 含義解釋:
操作符 <- 用於指定通道的方向,發送或接收。如果未指定方向,則爲雙向通道。
ch <- v // 把 v 發送到通道 ch
v := <-ch // 從 ch 接收數據// 並把值賦給 v
默認情況下,通道是不帶緩衝區的。無緩衝的通道必須有接收才能發送,發送端發送數據,同時必須有接收端相應的接收操作。
不帶緩存的:
package main
import (
"fmt"
"math/rand"
)
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 把 sum 發送到通道 c
}
func main() {
var s [10000000]int
for i := 0; i< 10000000;i++ {
s[i]= rand.Int()
}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 從通道 c 中接收
fmt.Println(x, y, x+y)
}
671395704509779677 -7495381818067143779 -6823986113557364102
Process finished with exit code 0
- channel操作
發送(send)、接收(receive)和關閉(close)
發送和接收都使用<-符號。
1.定義初始化
ch := make(chan int)
2.發送,將一個值發送到通道中。
ch <- 10 // 把10發送到ch中
3.接收,從一個通道中接收值。
x := <- ch // 從ch中接收值並賦值給變量x
<-ch // 從ch中接收值,忽略結果
4.關閉
調用內置的close函數關閉通道。
close(ch) //關閉通道不是必須的。
5.關閉後的通道特點:
對一個關閉的通道再發送值就會導致panic。
對一個關閉的通道進行接收會一直獲取值直到通道爲空。
對一個關閉的並且沒有值的通道執行接收操作會得到對應類型的零值。
關閉一個已經關閉的通道會導致panic。
package main
import (
"fmt"
)
func a() {
i := 0
defer fmt.Println(i) //在return 時候執行的棧空間的函數動作,此時的空間i 的值爲0
i++
return
}
func recv(c chan int) {
ret := <-c
fmt.Println("recv ch sucessed", ret)
}
func main() {
a()
ch := make(chan int) //不攜帶緩存的(默認的channel),需要先定義一個處理接受的
go recv(ch)
ch <- 10
fmt.Println("send ch sucessed")
}
API server listening at: 127.0.0.1:31820
0
recv ch sucessed 10
send ch sucessed
Process exiting with code: 0
- 有緩衝的通道
通道的容量大於零,該通道就是有緩衝的通道,通道的容量表示通道中能存放元素的數量。使用內置的len函數獲取通道內元素的數量,cap函數獲取通道的容量。
package main
import (
"fmt"
)
func Recv(c chan int) {
sum := <-c
fmt.Println("Recv sucessed", sum)
}
func main() {
ch := make(chan int, 1) // 創建一個容量爲1的有緩衝區通道
ch <- 10
Recv(ch)
fmt.Println("Send sucessed")
}
```go
API server listening at: 127.0.0.1:22864
Recv sucessed 10
Send sucessed
Process exiting with code: 0
GO語言中defer使用
將一個方法延遲到包裹該方法的方法返回時執行時候執行,
類似java C++ 的try…catch… ,C# using 的作用,有時候也用來處理關閉文件句柄等回收操作。
觸發時機:
1.包裹defer的函數返回時
2.包裹defer的函數執行到末尾時
3.所在的goroutine發生panic時
package main
import (
"fmt"
)
func a() {
i := 0
defer fmt.Println(i) //壓入棧空間時候i 已經等於0
i++
return
}
func main() {
a()
return
}
API server listening at: 127.0.0.1:38494
0
Process exiting with code: 0