Go基礎知識梳理(四)
GO的哲學是“不要通過共享記憶體來通信,而是通過通信來共享記憶體”,通道是GO通過通信來共享記憶體的載體,
rumtime包常用方法
runtime.NumGoroutine() //回傳當前程式的協程數量
runtime.GOMAXPROCS(0) //獲取當前的GOMAXPROCS數量
runtime.GOMAXPROCS(2) //設定程式的GOMAXPROCS數量為2
goroutine
特性
- 執行是非阻塞的,不會等待
- go 后面的回傳值會被忽略
- 調度器不能保證goroutine的執行順序
fun main() {
//另起一個協程去列印
go func() {
fmt.Println("goruntine")
}()
}
chan
//創建chan
c := make(chan dataType)
//無緩沖, len 和 cap 都是0
fmt.Println(len(c)) //0
fmt.Println(cap(c)) //0
//有緩沖
c = make(chan dataType, 10)
//len 代表沒有被讀取的元素數, cap 代表整個通道的容量
fmt.Println(len(c)) //0
fmt.Println(cap(c)) //10
WaitingGroup組件
Add(10) 給內置計數器加10
Done() 相當于Add(-1)
Wait() 內置計數器不為0則一直等待
// 寫法
func main() {
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func(i int) {
defer wg.Done()
fmt.Println(i)
time.Sleep(time.Millisecond * 3000)
}(i)
}
wg.Wait()
fmt.Println("done")
}
select
- 先打亂所有的case陳述句
- 遍歷case陳述句,查看是否已經讀寫了
- 選擇可讀寫的case去執行
- 沒有可讀寫的case,則查看default陳述句是否定義,再去執行
- 沒有defaul陳述句,則會等待可執行的case
看一段融合了并發,緩沖,退出通知等多重特性的代碼
func GenerateA(done chan struct{}) chan int {
ch := make(chan int, 5)
// fmt.Println("通道數+1")
go func() {
fmt.Println("執行緒數+A")
Label:
for {
select {
case res := <-done:
fmt.Println("done", res)
break Label
case ch <- rand.Int():
}
}
close(ch)
}()
return ch
}
func GenerateB(done chan struct{}) chan int {
ch := make(chan int, 5)
go func() {
fmt.Println("執行緒數+B")
Label:
for {
select {
case res := <-done:
fmt.Println("done", res)
break Label
case ch <- rand.Int():
}
}
close(ch)
}()
return ch
}
func GenerateInt(done chan struct{}) chan int {
//無緩沖通道
ch := make(chan int)
send := make(chan struct{})
go func() {
Label:
for {
select {
case <-done:
send <- struct{}{}
send <- struct{}{}
break Label
case ch <- <-GenerateA(send):
fmt.Println("chose A")
case ch <- <-GenerateB(send):
fmt.Println("chose B")
}
}
close(ch)
}()
return ch
}
func main() {
done := make(chan struct{})
ch := GenerateInt(done)
fmt.Println(runtime.NumGoroutine())
for i := 0; i < 10; i++ {
fmt.Println(<-ch)
}
fmt.Println(runtime.NumGoroutine())
done <- struct{}{}
fmt.Println("stop gernate", struct{}{})
time.Sleep(1 * time.Second) //等待1s,讓停止的goruntime列印,如果不加這句話,可能會導致主執行緒比新起的協程早退出,從而無法列印出done {}
}
列印結果不展示,其中發現的問題:
1.列印出來的數字長度不固定
2.每次Select查看case是否堵塞的時候,都會執行一次該方法
Context
func main() {
ctxa, cancel := context.WithCancel(context.Background())
go work(ctxa, "work1")
tm := time.Now().Add(3 * time.Second)
ctxb, _ := context.WithDeadline(ctxa, tm)
go work(ctxb, "work2")
oc := OtherContext{ctxb}
ctxc := context.WithValue(oc, "key", "andes, pass from main")
go workWithValue(ctxc, "work3")
time.Sleep(10 * time.Second)
cancel()
time.Sleep(5 * time.Second)
fmt.Println("main stop")
}
type OtherContext struct {
context.Context
}
func work(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Printf("%s get msg to cancel\n", name)
return
default:
fmt.Printf("%s is running \n", name)
time.Sleep(1 * time.Second)
}
}
}
func workWithValue(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Printf("%s get msg to cancel\n", name)
return
default:
value := ctx.Value("key").(string)
fmt.Printf("%s is running value=https://www.cnblogs.com/xiaofua/p/%s /n", name, value)
time.Sleep(1 * time.Second)
}
}
}
這段代碼中,都是一條鏈路下來的
根節點 context.Background() -> ctxa -> ctxb -> oc
其中ctxa加了個時間控制,所以到達一定的時間就會自動關閉
oc附帶了個鍵對值
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/423523.html
標籤:Go
上一篇:【第十四期】高德go面經
