欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          一文聊聊Go語言中資源競爭問題

          一文聊聊Go語言中資源競爭問題

          我們都知道,在并發(fā)編程中,線程安全是非常重要的。接下來我們就假定一個場景,復(fù)現(xiàn)一下線程不安全的情況,再聊聊如何在Go中解決

          場景

          我們現(xiàn)在需要對1~100求他們的階乘,并將結(jié)果放到一個map中

          1! = 1 = 1 2! = 1 * 2 = 2 3! = 1 * 2 * 3 = 6 4! = 1 * 2 * 3 * 4 = 24 5! = 1 * 2 * 3 * 4 * 5 = 120 ... {     1: 1     2: 2     3: 6     4: 24     5: 120     ... }
          登錄后復(fù)制

          代碼實現(xiàn)

          var factorialMap = make(map[int]int)  func Factorial(n int) {     result := 1     for i := 1; i <= n; i++ {         result *= i     }     factorialMap[n] = result }  func main() {     for i := 1; i < 10; i++ {         Factorial(i)     }     for k, v := range factorialMap {         fmt.Printf("%d 的階乘是%dn", k, v)     } }
          登錄后復(fù)制

          一文聊聊Go語言中資源競爭問題上述代碼執(zhí)行結(jié)果其實是沒問題的,為什么會出現(xiàn)亂序呢?因為這是go語言中map其實就是亂序的,按照我們的理解,先存的先出,但是不好意思,Golang的map不是這樣的。 上面執(zhí)行也沒什么問題啊,細心的同學(xué)可能發(fā)現(xiàn)了,這個版本的代碼并沒有用上并發(fā),對吧。好接下來我們繼續(xù)改進

          并發(fā)實現(xiàn)

          var factorialMap = make(map[int]int)  func Factorial(n int) {     result := 1     for i := 1; i <= n; i++ {         result *= i     }     factorialMap[n] = result }  func main() {     for i := 1; i < 10; i++ {         go Factorial(i)     }     for k, v := range factorialMap {         fmt.Printf("%d 的階乘是%dn", k, v)     } }
          登錄后復(fù)制

          一文聊聊Go語言中資源競爭問題我們可以發(fā)現(xiàn),并發(fā)版就是在調(diào)用計算階乘函數(shù)的前面加上了一個go而已。不要小看這個go,扯遠了,當然大家知道這是go語言中開啟一個協(xié)程的關(guān)鍵字即可。

          執(zhí)行結(jié)果就是,控制臺啥都沒輸出,這是因為主協(xié)程和子協(xié)程之間的執(zhí)行關(guān)系,下面我們畫圖理解

          一文聊聊Go語言中資源競爭問題從上圖中我們可以發(fā)現(xiàn),主協(xié)程執(zhí)行的時間短(表現(xiàn)在比較短),子協(xié)程執(zhí)行時間比較長(表現(xiàn)在比較長) 我們一定要記住,子協(xié)程是相對于當前的主協(xié)程來說的,如果主協(xié)程不存在了,那就沒有子協(xié)程了

          所以上面代碼啥都沒輸出就是因為,主協(xié)程已經(jīng)執(zhí)行完了,但是子協(xié)程還沒做完,那子協(xié)程都沒做完,factorialMap中能有東西嗎?

          主等子

          這就引出我們第一個問題,主協(xié)程如何等待子協(xié)程執(zhí)行完再退出程序。我們現(xiàn)在用一個最簡單,最容易想到的做法

          var factorialMap = make(map[int]int)  func Factorial(n int) {     result := 1     for i := 1; i <= n; i++ {         result *= i     }     factorialMap[n] = result }  func main() {     for i := 1; i < 100; i++ {         go Factorial(i)     }     time.Sleep(time.Second * 3)     for k, v := range factorialMap {         fmt.Printf("%d 的階乘是%dn", k, v)     } }
          登錄后復(fù)制

          一文聊聊Go語言中資源競爭問題當并發(fā)數(shù)比較小的時候,這個問題可能不會出現(xiàn),一旦并發(fā)數(shù)變大,問題就立馬出現(xiàn)了

          圖中的執(zhí)行結(jié)果是并發(fā)map寫入錯誤為什么會出現(xiàn)這個問題,我們假設(shè)100個人往一個籃子里放水果,很容易。但是100個人從一個籃子里拿水果,那就會出問題,首先,籃子里的水果不一定夠100個,其二每個人都想先拿,必然會引起爭搶。

          問題一優(yōu)化

          針對上面的問題,我們引入全局鎖的概念。這就有點像我們上廁所,100個人都想上廁所,但廁所只有1個,誰先搶到了誰先上,并且這個人還有給廁所上鎖,防止其他人進來

          一文聊聊Go語言中資源競爭問題

          var factorialMap = make(map[int]int) var lock sync.Mutex  func Factorial(n int) {     result := 1     for i := 1; i <= n; i++ {             result *= i     }     // defer 不好理解     // defer func(){     // 	lock.Unlock() // 執(zhí)行完解鎖     // }()     lock.Lock() // 執(zhí)行時上鎖     factorialMap[n] = result     lock.Unlock() // 執(zhí)行后解鎖 }  func main() {     for i := 1; i < 100; i++ {         go Factorial(i)     }     time.Sleep(time.Second * 3)     for k, v := range factorialMap {         fmt.Printf("%d 的階乘是%dn", k, v)     } }
          登錄后復(fù)制

          一文聊聊Go語言中資源競爭問題執(zhí)行結(jié)果有0可能是數(shù)據(jù)類型存不下了導(dǎo)致的,這個大家不用關(guān)心

          一文聊聊Go語言中資源競爭問題這樣我們就解決了資源競爭的問題了。但其實還有一個問題,就是我們在主協(xié)程中還是必須手動等待,這要非常不好,那如果子協(xié)程3秒內(nèi)解決不了怎么辦?

          問題二優(yōu)化

          這個問題是我們不想在主協(xié)程中手動等待子協(xié)程,換句話說是我們不想直接在代碼中寫明要等待多長時間

          這里我們就引入了WaitGroup

          var factorialMap = make(map[int]int) var lock sync.Mutex var wg sync.WaitGroup  func Factorial(n int) {     result := 1     for i := 1; i <= n; i++ {         result *= i     }     lock.Lock() // 執(zhí)行時上鎖     factorialMap[n] = result     lock.Unlock() // 執(zhí)行后解鎖     wg.Done() }  func main() {     for i := 1; i < 100; i++ {         wg.Add(1)         go Factorial(i)     }     wg.Wait()     for k, v := range factorialMap {         fmt.Printf("%d 的階乘是%dn", k, v)     } }
          登錄后復(fù)制

          WaitGroup的內(nèi)部原理大家自己細扣,我這就不講了 總結(jié)來說就是WaitGroup是一個籃子,每開一個協(xié)程,就往籃子中加一個標識(Add函數(shù)),每執(zhí)行完一個協(xié)程,就從籃子中減去一個標識(Done函數(shù)),最后查看籃子中,如果是空的,就表示協(xié)程執(zhí)行完了(Wait函數(shù))

          【推薦學(xué)習:go視頻教程】

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號