欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

GO語言臨界資源安全問題的深入理解

 更新時間:2021年12月09日 10:24:08   作者:Davie老師  
臨界資源安全問題也就是以往我們常聽到的線程安全問題,本文詳細的介紹了GO語言臨界資源安全問題的深入理解,具有一定的參考價值,感興趣的小伙伴們可以參考一下

一、臨界資源

臨界資源: 指并發(fā)環(huán)境中多個進程/線程/協(xié)程共享的資源。

但是在并發(fā)編程中對臨界資源的處理不當, 往往會導致數(shù)據(jù)不一致的問題。

示例代碼:

package main
?
import (
    "fmt"
    "time"
)
?
func main()  {
    a := 1
    go func() {
        a = 2
        fmt.Println("子goroutine。。",a)
    }()
    a = 3
    time.Sleep(1)
    fmt.Println("main goroutine。。",a)
}

我們通過終端命令來執(zhí)行:

能夠發(fā)現(xiàn)一處被多個goroutine共享的數(shù)據(jù)。

二、臨界資源安全問題

并發(fā)本身并不復雜,但是因為有了資源競爭的問題,就使得我們開發(fā)出好的并發(fā)程序變得復雜起來,因為會引起很多莫名其妙的問題。

如果多個goroutine在訪問同一個數(shù)據(jù)資源的時候,其中一個線程修改了數(shù)據(jù),那么這個數(shù)值就被修改了,對于其他的goroutine來講,這個數(shù)值可能是不對的。

舉個例子,我們通過并發(fā)來實現(xiàn)火車站售票這個程序。一共有100張票,4個售票口同時出售。

我們先來看一下示例代碼:

package main
?
import (
    "fmt"
    "math/rand"
    "time"
)
?
//全局變量
var ticket = 10 // 100張票
?
func main() {
    /*
    4個goroutine,模擬4個售票口,4個子程序操作同一個共享數(shù)據(jù)。
     */
    go saleTickets("售票口1") // g1,100
    go saleTickets("售票口2") // g2,100
    go saleTickets("售票口3") //g3,100
    go saleTickets("售票口4") //g4,100
?
    time.Sleep(5*time.Second)
}
?
func saleTickets(name string) {
    rand.Seed(time.Now().UnixNano())
    //for i:=1;i<=100;i++{
    //  fmt.Println(name,"售出:",i)
    //}
    for { //ticket=1
        if ticket > 0 { //g1,g3,g2,g4
            //睡眠
            time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
            // g1 ,g3, g2,g4
            fmt.Println(name, "售出:", ticket)  // 1 , 0, -1 , -2
            ticket--   //0 , -1 ,-2 , -3
        } else {
            fmt.Println(name,"售罄,沒有票了。。")
            break
        }
    }
}
?

我們?yōu)榱烁玫挠^察臨界資源問題,每個goroutine先睡眠一個隨機數(shù),然后再售票,我們發(fā)現(xiàn)程序的運行結(jié)果,還可以賣出編號為負數(shù)的票。

分析:

我們的賣票邏輯是先判斷票數(shù)的編號是否為負數(shù),如果大于0,然后我們就進行賣票,只不過在賣票錢先睡眠,然后再賣,假如說此時已經(jīng)賣票到只剩最后1張了,某一個goroutine持有了CPU的時間片,那么它再片段是否有票的時候,條件是成立的,所以它可以賣票編號為1的最后一張票。但是因為它在賣之前,先睡眠了,那么其他的goroutine就會持有CPU的時間片,而此時這張票還沒有被賣出,那么第二個goroutine再判斷是否有票的時候,條件也是成立的,那么它可以賣出這張票,然而它也進入了睡眠。。其他的第三個第四個goroutine都是這樣的邏輯,當某個goroutine醒來的時候,不會再判斷是否有票,而是直接售出,這樣就賣出最后一張票了,然而其他的goroutine醒來的時候,就會陸續(xù)賣出了第0張,-1張,-2張。

這就是臨界資源的不安全問題。某一個goroutine在訪問某個數(shù)據(jù)資源的時候,按照數(shù)值,已經(jīng)判斷好了條件,然后又被其他的goroutine搶占了資源,并修改了數(shù)值,等這個goroutine再繼續(xù)訪問這個數(shù)據(jù)的時候,數(shù)值已經(jīng)不對了。

三、臨界資源安全問題的解決

要想解決臨界資源安全的問題,很多編程語言的解決方案都是同步。通過上鎖的方式,某一時間段,只能允許一個goroutine來訪問這個共享數(shù)據(jù),當前goroutine訪問完畢,解鎖后,其他的goroutine才能來訪問。

我們可以借助于sync包下的鎖操作。

示例代碼:

package main
?
import (
    "fmt"
    "math/rand"
    "time"
    "sync"
)
?
//全局變量
var ticket = 10 // 100張票
?
var wg sync.WaitGroup
var matex sync.Mutex // 創(chuàng)建鎖頭
?
func main() {
    /*
    4個goroutine,模擬4個售票口,4個子程序操作同一個共享數(shù)據(jù)。
     */
    wg.Add(4)
    go saleTickets("售票口1") // g1,100
    go saleTickets("售票口2") // g2,100
    go saleTickets("售票口3") //g3,100
    go saleTickets("售票口4") //g4,100
    wg.Wait()              // main要等待。。。
?
    //time.Sleep(5*time.Second)
}
?
func saleTickets(name string) {
    rand.Seed(time.Now().UnixNano())
    defer wg.Done()
    //for i:=1;i<=100;i++{
    //  fmt.Println(name,"售出:",i)
    //}
    for { //ticket=1
        matex.Lock()
        if ticket > 0 { //g1,g3,g2,g4
            //睡眠
            time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
            // g1 ,g3, g2,g4
            fmt.Println(name, "售出:", ticket) // 1 , 0, -1 , -2
            ticket--                         //0 , -1 ,-2 , -3
        } else {
            matex.Unlock() //解鎖
            fmt.Println(name, "售罄,沒有票了。。")
            break
        }
        matex.Unlock() //解鎖
    }
}
?

運行結(jié)果:

四、寫在最后

在Go的并發(fā)編程中有一句很經(jīng)典的話:不要以共享內(nèi)存的方式去通信,而要以通信的方式去共享內(nèi)存。

在Go語言中并不鼓勵用鎖保護共享狀態(tài)的方式在不同的Goroutine中分享信息(以共享內(nèi)存的方式去通信)。而是鼓勵通過channel將共享狀態(tài)或共享狀態(tài)的變化在各個Goroutine之間傳遞(以通信的方式去共享內(nèi)存),這樣同樣能像用鎖一樣保證在同一的時間只有一個Goroutine訪問共享狀態(tài)。

當然,在主流的編程語言中為了保證多線程之間共享數(shù)據(jù)安全性和一致性,都會提供一套基本的同步工具集,如鎖,條件變量,原子操作等等。Go語言標準庫也毫不意外的提供了這些同步機制,使用方式也和其他語言也差不多。

到此這篇關(guān)于GO語言臨界資源安全問題的深入理解的文章就介紹到這了,更多相關(guān)GO語言臨界資源安全 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 細細探究Go 泛型generic設(shè)計

    細細探究Go 泛型generic設(shè)計

    這篇文章主要帶大家細細探究了Go 泛型generic設(shè)計及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Golang實現(xiàn)對map的并發(fā)讀寫的方法示例

    Golang實現(xiàn)對map的并發(fā)讀寫的方法示例

    這篇文章主要介紹了Golang實現(xiàn)對map的并發(fā)讀寫的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-03-03
  • Go語言之init函數(shù)

    Go語言之init函數(shù)

    Go語言有一個特殊的函數(shù)init,先于main函數(shù)執(zhí)行,實現(xiàn)包級別的一些初始化操作。這篇文章介紹了Go中的Init函數(shù),對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • 使用golang寫一個redis-cli的方法示例

    使用golang寫一個redis-cli的方法示例

    這篇文章主要介紹了使用golang寫一個redis-cli的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-10-10
  • Go并發(fā)控制Channel使用場景分析

    Go并發(fā)控制Channel使用場景分析

    使用channel來控制子協(xié)程的優(yōu)點是實現(xiàn)簡單,缺點是當需要大量創(chuàng)建協(xié)程時就需要有相同數(shù)量的channel,而且對于子協(xié)程繼續(xù)派生出來的協(xié)程不方便控制
    2021-07-07
  • Golang map實踐及實現(xiàn)原理解析

    Golang map實踐及實現(xiàn)原理解析

    這篇文章主要介紹了Golang map實踐以及實現(xiàn)原理,Go 語言中,通過哈希查找表實現(xiàn) map,用鏈表法解決哈希沖突,本文結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2022-06-06
  • golang使用net/rpc庫實現(xiàn)rpc

    golang使用net/rpc庫實現(xiàn)rpc

    這篇文章主要為大家詳細介紹了golang如何使用net/rpc庫實現(xiàn)rpc,文章的示例代碼講解詳細,具有一定的借鑒價值,需要的小伙伴可以參考一下
    2024-01-01
  • go for range遍歷二維數(shù)組的示例

    go for range遍歷二維數(shù)組的示例

    今天小編就為大家分享一篇關(guān)于go for range遍歷二維數(shù)組的示例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • 深入string理解Golang是怎樣實現(xiàn)的

    深入string理解Golang是怎樣實現(xiàn)的

    這篇文章主要為大家介紹了深入string理解Golang是怎樣實現(xiàn)的原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Golang語言如何高效拼接字符串詳解

    Golang語言如何高效拼接字符串詳解

    最近在做性能優(yōu)化,有個函數(shù)里面的耗時特別長,看里面的操作大多是一些字符串拼接的操作,而字符串拼接在 golang 里面其實有很多種實現(xiàn),下面這篇文章主要給大家介紹了關(guān)于Golang語言如何高效拼接字符串的相關(guān)資料,需要的朋友可以參考下
    2021-11-11

最新評論