成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go語(yǔ)言下的并發(fā)編程:Goroutine,Channel 和 Sync

開(kāi)發(fā) 后端
在當(dāng)今這個(gè)多核時(shí)代,并發(fā)編程的意義不言而喻。使用 Go 開(kāi)發(fā)并發(fā)程序,操作起來(lái)非常簡(jiǎn)單,語(yǔ)言級(jí)別提供關(guān)鍵字 go 用于啟動(dòng)協(xié)程,并且在同一臺(tái)機(jī)器上可以啟動(dòng)成千上萬(wàn)個(gè)協(xié)程。

[[426818]]

優(yōu)雅的并發(fā)編程范式,完善的并發(fā)支持,出色的并發(fā)性能是 Go 語(yǔ)言區(qū)別于其他語(yǔ)言的一大特色。

在當(dāng)今這個(gè)多核時(shí)代,并發(fā)編程的意義不言而喻。使用 Go 開(kāi)發(fā)并發(fā)程序,操作起來(lái)非常簡(jiǎn)單,語(yǔ)言級(jí)別提供關(guān)鍵字 go 用于啟動(dòng)協(xié)程,并且在同一臺(tái)機(jī)器上可以啟動(dòng)成千上萬(wàn)個(gè)協(xié)程。

下面就來(lái)詳細(xì)介紹。

goroutine

Go 語(yǔ)言的并發(fā)執(zhí)行體稱(chēng)為 goroutine,使用關(guān)鍵詞 go 來(lái)啟動(dòng)一個(gè) goroutine。

go 關(guān)鍵詞后面必須跟一個(gè)函數(shù),可以是有名函數(shù),也可以是無(wú)名函數(shù),函數(shù)的返回值會(huì)被忽略。

go 的執(zhí)行是非阻塞的。

先來(lái)看一個(gè)例子:

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "time" 
  6.  
  7. func main() { 
  8.     go spinner(100 * time.Millisecond) 
  9.     const n = 45 
  10.     fibN := fib(n) 
  11.     fmt.Printf("\rFibonacci(%d) = %d\n", n, fibN) // Fibonacci(45) = 1134903170 
  12.  
  13. func spinner(delay time.Duration) { 
  14.     for { 
  15.         for _, r := range `-\|/` { 
  16.             fmt.Printf("\r%c", r) 
  17.             time.Sleep(delay) 
  18.         } 
  19.     } 
  20.  
  21. func fib(x intint { 
  22.     if x < 2 { 
  23.         return x 
  24.     } 
  25.     return fib(x-1) + fib(x-2) 

從執(zhí)行結(jié)果來(lái)看,成功計(jì)算出了斐波那契數(shù)列的值,說(shuō)明程序在 spinner 處并沒(méi)有阻塞,而且 spinner 函數(shù)還一直在屏幕上打印提示字符,說(shuō)明程序正在執(zhí)行。

當(dāng)計(jì)算完斐波那契數(shù)列的值,main 函數(shù)打印結(jié)果并退出,spinner 也跟著退出。

再來(lái)看一個(gè)例子,循環(huán)執(zhí)行 10 次,打印兩個(gè)數(shù)的和:

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. func Add(x, y int) { 
  6.     z := x + y 
  7.     fmt.Println(z) 
  8.  
  9. func main() { 
  10.     for i := 0; i < 10; i++ { 
  11.         go Add(i, i) 
  12.     } 

有問(wèn)題了,屏幕上什么都沒(méi)有,為什么呢?

這就要看 Go 程序的執(zhí)行機(jī)制了。當(dāng)一個(gè)程序啟動(dòng)時(shí),只有一個(gè) goroutine 來(lái)調(diào)用 main 函數(shù),稱(chēng)為主 goroutine。新的 goroutine 通過(guò) go 關(guān)鍵詞創(chuàng)建,然后并發(fā)執(zhí)行。當(dāng) main 函數(shù)返回時(shí),不會(huì)等待其他 goroutine 執(zhí)行完,而是直接暴力結(jié)束所有 goroutine。

那有沒(méi)有辦法解決呢?當(dāng)然是有的,請(qǐng)往下看。

channel

一般寫(xiě)多進(jìn)程程序時(shí),都會(huì)遇到一個(gè)問(wèn)題:進(jìn)程間通信。常見(jiàn)的通信方式有信號(hào),共享內(nèi)存等。goroutine 之間的通信機(jī)制是通道 channel。

使用 make 創(chuàng)建通道:

  1. ch := make(chan int) // ch 的類(lèi)型是 chan int 

通道支持三個(gè)主要操作:send,receive 和 close。

  1. ch <- x // 發(fā)送 
  2. x = <-ch // 接收 
  3. <-ch // 接收,丟棄結(jié)果 
  4.  
  5. close(ch) // 關(guān)閉 

無(wú)緩沖 channel

make 函數(shù)接受兩個(gè)參數(shù),第二個(gè)參數(shù)是可選參數(shù),表示通道容量。不傳或者傳 0 表示創(chuàng)建了一個(gè)無(wú)緩沖通道。

無(wú)緩沖通道上的發(fā)送操作將會(huì)阻塞,直到另一個(gè) goroutine 在對(duì)應(yīng)的通道上執(zhí)行接收操作。相反,如果接收先執(zhí)行,那么接收 goroutine 將會(huì)阻塞,直到另一個(gè) goroutine 在對(duì)應(yīng)通道上執(zhí)行發(fā)送。

所以,無(wú)緩沖通道是一種同步通道。

下面我們使用無(wú)緩沖通道把上面例子中出現(xiàn)的問(wèn)題解決一下。

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. func Add(x, y int, ch chan int) { 
  6.     z := x + y 
  7.     ch <- z 
  8.  
  9. func main() { 
  10.  
  11.     ch := make(chan int
  12.     for i := 0; i < 10; i++ { 
  13.         go Add(i, i, ch) 
  14.     } 
  15.  
  16.     for i := 0; i < 10; i++ { 
  17.         fmt.Println(<-ch) 
  18.     } 

可以正常輸出結(jié)果。

主 goroutine 會(huì)阻塞,直到讀取到通道中的值,程序繼續(xù)執(zhí)行,最后退出。

緩沖 channel

創(chuàng)建一個(gè)容量是 5 的緩沖通道:

  1. ch := make(chan int, 5) 

緩沖通道的發(fā)送操作在通道尾部插入一個(gè)元素,接收操作從通道的頭部移除一個(gè)元素。如果通道滿(mǎn)了,發(fā)送會(huì)阻塞,直到另一個(gè) goroutine 執(zhí)行接收。相反,如果通道是空的,接收會(huì)阻塞,直到另一個(gè) goroutine 執(zhí)行發(fā)送。

有沒(méi)有感覺(jué),其實(shí)緩沖通道和隊(duì)列一樣,把操作都解耦了。

單向 channel

類(lèi)型 chan<- int 是一個(gè)只能發(fā)送的通道,類(lèi)型 <-chan int 是一個(gè)只能接收的通道。

任何雙向通道都可以用作單向通道,但反過(guò)來(lái)不行。

還有一點(diǎn)需要注意,close 只能用在發(fā)送通道上,如果用在接收通道會(huì)報(bào)錯(cuò)。

看一個(gè)單向通道的例子:

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. func counter(out chan<- int) { 
  6.     for x := 0; x < 10; x++ { 
  7.         out <- x 
  8.     } 
  9.     close(out
  10.  
  11. func squarer(out chan<- intin <-chan int) { 
  12.     for v := range in { 
  13.         out <- v * v 
  14.     } 
  15.     close(out
  16.  
  17. func printer(in <-chan int) { 
  18.     for v := range in { 
  19.         fmt.Println(v) 
  20.     } 
  21.  
  22. func main() { 
  23.     n := make(chan int
  24.     s := make(chan int
  25.  
  26.     go counter(n) 
  27.     go squarer(s, n) 
  28.     printer(s) 
  29.  

sync

sync 包提供了兩種鎖類(lèi)型:sync.Mutex 和 sync.RWMutex,前者是互斥鎖,后者是讀寫(xiě)鎖。

當(dāng)一個(gè) goroutine 獲取了 Mutex 后,其他 goroutine 不管讀寫(xiě),只能等待,直到鎖被釋放。

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "sync" 
  6.     "time" 
  7.  
  8. func main() { 
  9.     var mutex sync.Mutex 
  10.     wg := sync.WaitGroup{} 
  11.  
  12.     // 主 goroutine 先獲取鎖 
  13.     fmt.Println("Locking  (G0)"
  14.     mutex.Lock() 
  15.     fmt.Println("locked (G0)"
  16.  
  17.     wg.Add(3) 
  18.     for i := 1; i < 4; i++ { 
  19.         go func(i int) { 
  20.             // 由于主 goroutine 先獲取鎖,程序開(kāi)始 5 秒會(huì)阻塞在這里 
  21.             fmt.Printf("Locking (G%d)\n", i) 
  22.             mutex.Lock() 
  23.             fmt.Printf("locked (G%d)\n", i) 
  24.  
  25.             time.Sleep(time.Second * 2) 
  26.             mutex.Unlock() 
  27.             fmt.Printf("unlocked (G%d)\n", i) 
  28.  
  29.             wg.Done() 
  30.         }(i) 
  31.     } 
  32.  
  33.     // 主 goroutine 5 秒后釋放鎖 
  34.     time.Sleep(time.Second * 5) 
  35.     fmt.Println("ready unlock (G0)"
  36.     mutex.Unlock() 
  37.     fmt.Println("unlocked (G0)"
  38.  
  39.     wg.Wait() 

RWMutex 屬于經(jīng)典的單寫(xiě)多讀模型,當(dāng)讀鎖被占用時(shí),會(huì)阻止寫(xiě),但不阻止讀。而寫(xiě)鎖會(huì)阻止寫(xiě)和讀。

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "sync" 
  6.     "time" 
  7.  
  8. func main() { 
  9.     var rwMutex sync.RWMutex 
  10.     wg := sync.WaitGroup{} 
  11.  
  12.     Data := 0 
  13.     wg.Add(20) 
  14.     for i := 0; i < 10; i++ { 
  15.         go func(t int) { 
  16.             // 第一次運(yùn)行后,寫(xiě)解鎖。 
  17.             // 循環(huán)到第二次時(shí),讀鎖定后,goroutine 沒(méi)有阻塞,同時(shí)讀成功。 
  18.             fmt.Println("Locking"
  19.             rwMutex.RLock() 
  20.             defer rwMutex.RUnlock() 
  21.             fmt.Printf("Read data: %v\n", Data) 
  22.             wg.Done() 
  23.             time.Sleep(2 * time.Second
  24.         }(i) 
  25.         go func(t int) { 
  26.             // 寫(xiě)鎖定下是需要解鎖后才能寫(xiě)的 
  27.             rwMutex.Lock() 
  28.             defer rwMutex.Unlock() 
  29.             Data += t 
  30.             fmt.Printf("Write Data: %v %d \n", Data, t) 
  31.             wg.Done() 
  32.             time.Sleep(2 * time.Second
  33.         }(i) 
  34.     } 
  35.  
  36.     wg.Wait() 

總結(jié)

并發(fā)編程算是 Go 的特色,也是核心功能之一了,涉及的知識(shí)點(diǎn)其實(shí)是非常多的,本文也只是起到一個(gè)拋磚引玉的作用而已。

本文開(kāi)始介紹了 goroutine 的簡(jiǎn)單用法,然后引出了通道的概念。

通道有三種:

  1. 無(wú)緩沖通道
  2. 緩沖通道
  3. 單向通道

最后介紹了 Go 中的鎖機(jī)制,分別是 sync 包提供的 sync.Mutex(互斥鎖) 和 sync.RWMutex(讀寫(xiě)鎖)。

goroutine 博大精深,后面的坑還是要慢慢踩的。

 

責(zé)任編輯:姜華 來(lái)源: AlwaysBeta
相關(guān)推薦

2024-09-06 10:48:13

2024-10-14 08:51:52

協(xié)程Go語(yǔ)言

2024-06-19 10:08:34

GoChannel工具

2025-01-15 09:13:53

2021-07-06 07:46:07

Go語(yǔ)言編程

2022-03-04 10:07:45

Go語(yǔ)言字節(jié)池

2025-01-16 09:43:10

2023-02-10 09:40:36

Go語(yǔ)言并發(fā)

2023-12-29 08:42:46

高并發(fā)Go語(yǔ)言

2021-06-29 23:40:19

Golang語(yǔ)言并發(fā)

2024-12-13 16:28:43

2022-08-08 08:31:55

Go 語(yǔ)言閉包匿名函數(shù)

2022-08-08 06:50:06

Go語(yǔ)言閉包

2023-12-25 09:58:25

sync包Go編程

2023-11-28 08:01:48

互斥鎖共享資源

2025-03-24 00:25:00

Go語(yǔ)言并發(fā)編程

2025-04-03 09:12:26

GolangWaitGroup工具

2022-10-17 08:07:13

Go 語(yǔ)言并發(fā)編程

2023-05-24 09:31:51

CGo

2020-12-27 10:15:44

Go語(yǔ)言channel管道
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 91欧美| 精品一区二区久久久久久久网站 | 成人在线免费观看 | 日韩精品一区二区三区四区 | 国产激情第一页 | 自拍视频精品 | 免费国产一区二区 | h片在线免费看 | 日本久久网 | 精品欧美一区二区三区久久久 | 欧美一区二区在线观看 | 黄色片a级 | 久久综合入口 | 欧美久久久久久久久中文字幕 | 亚洲视频区 | 日本成人中文字幕 | 日日综合 | 日本午夜免费福利视频 | 欧美日韩一本 | 久久久这里都是精品 | 色网站在线 | 激情欧美日韩一区二区 | 亚洲欧美精品在线观看 | 夜夜爽99久久国产综合精品女不卡 | 免费国产一区二区 | 国产高清久久久 | 九九热精品视频在线观看 | 看一级黄色毛片 | av黄色在线观看 | 日韩在线免费播放 | 成人a视频在线观看 | 国产精成人| 亚洲精品在线观看网站 | 成年女人免费v片 | 中文字幕一区二区三区四区不卡 | 一本岛道一二三不卡区 | 欧美日韩中文字幕在线播放 | 成人在线精品视频 | 国产三区在线观看视频 | 国产韩国精品一区二区三区 | 成年免费大片黄在线观看岛国 |