最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go并發(fā)編程之死鎖與活鎖的案例分析

 更新時(shí)間:2023年04月30日 08:47:27   作者:不背鍋運(yùn)維  
死鎖就是在并發(fā)程序中,兩個(gè)或多個(gè)線程彼此等待對(duì)方完成操作,從而導(dǎo)致它們都被阻塞,并無(wú)限期地等待對(duì)方完成;活鎖就是程序一直在運(yùn)行,但是無(wú)法取得進(jìn)展。本文將從一些案例出發(fā),分析一下它們,希望對(duì)大家有所幫助

什么是死鎖、活鎖

什么是死鎖:就是在并發(fā)程序中,兩個(gè)或多個(gè)線程彼此等待對(duì)方完成操作,從而導(dǎo)致它們都被阻塞,并無(wú)限期地等待對(duì)方完成。這種情況下,程序會(huì)卡死,無(wú)法繼續(xù)執(zhí)行。

什么是活鎖:就是程序一直在運(yùn)行,但是無(wú)法取得進(jìn)展。例如,在某些情況下,多個(gè)線程會(huì)爭(zhēng)奪同一個(gè)資源,然后每個(gè)線程都會(huì)釋放資源,以便其他線程可以使用它。但是,如果沒(méi)有正確的同步,這些線程可能會(huì)同時(shí)嘗試獲取該資源,然后再次釋放它。這可能導(dǎo)致線程在無(wú)限循環(huán)中運(yùn)行,卻無(wú)法取得進(jìn)展。

發(fā)生死鎖的案例分析

1.編寫會(huì)發(fā)生死鎖的代碼:

package?main

import?(
?"fmt"
?"sync"
)

func?main()?{
?var?mu?sync.Mutex
?mu.Lock()
?defer?mu.Unlock()

?wg?:=?sync.WaitGroup{}
?wg.Add(1)
?go?func()?{
??fmt.Println("goroutine?started")
??mu.Lock()?//?在這里獲取了鎖
??fmt.Println("goroutine?finished")
??mu.Unlock()
??wg.Done()
?}()

?wg.Wait()
}

運(yùn)行和輸出:

[root@workhost temp02]# go run main.go 
goroutine started
fatal error: all goroutines are asleep - deadlock! # 錯(cuò)誤很明顯了,告訴你死鎖啦!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc000010030?)
        /usr/local/go/src/runtime/sema.go:62 +0x27
...
...

上面的代碼,使用 sync.Mutex 實(shí)現(xiàn)了一個(gè)互斥鎖。主 goroutine 獲取了鎖,并啟動(dòng)了一個(gè)新的 goroutine。新 goroutine 也嘗試獲取鎖來(lái)執(zhí)行其任務(wù)。但是,由于主 goroutine 沒(méi)有釋放鎖,新 goroutine 將一直等待鎖,導(dǎo)致死鎖。

2.代碼改造

在上面的代碼中,可以通過(guò)將主 goroutine 中的 defer mu.Unlock() 移到 goroutine 函數(shù)中的 mu.Unlock() 后面來(lái)解決問(wèn)題。這樣,當(dāng) goroutine 獲取到鎖后,它可以在完成任務(wù)后釋放鎖,以便主 goroutine 可以繼續(xù)執(zhí)行。

改造后的代碼:

package?main

import?(
?"fmt"
?"sync"
)

func?main()?{
?var?mu?sync.Mutex
?mu.Lock()
?wg?:=?sync.WaitGroup{}
?wg.Add(1)
?go?func()?{
??fmt.Println("goroutine?started")
??mu.Lock()?//?在這里獲取了鎖
??fmt.Println("goroutine?finished")
??mu.Unlock()
??wg.Done()
?}()
?mu.Unlock()?//?釋放鎖
?wg.Wait()
}

運(yùn)行和輸出:

[root@workhost temp02]# go run main.go 
goroutine started
goroutine finished

3.如何避免死鎖

在 Go 語(yǔ)言中,要避免死鎖,一定要清楚以下幾個(gè)規(guī)則:

  • 避免嵌套鎖:在使用多個(gè)鎖時(shí),確保它們的嵌套順序相同。否則,可能會(huì)出現(xiàn)循環(huán)等待的情況,導(dǎo)致死鎖。
  • 避免無(wú)限等待:如果在獲取鎖時(shí)指定了超時(shí)時(shí)間,確保在超時(shí)后能夠處理錯(cuò)誤或執(zhí)行其他操作。
  • 避免過(guò)度競(jìng)爭(zhēng):如果多個(gè)協(xié)程需要訪問(wèn)相同的資源,請(qǐng)確保它們不會(huì)互相干擾。可以使用互斥鎖或讀寫鎖等機(jī)制來(lái)解決競(jìng)爭(zhēng)問(wèn)題。
  • 使用通道:Go 語(yǔ)言中的通道可以用于協(xié)調(diào)并發(fā)操作。使用通道來(lái)傳遞消息和同步操作,可以避免死鎖和競(jìng)爭(zhēng)問(wèn)題。
  • 確保資源釋放:在使用鎖或其他資源時(shí),一定要確保它們?cè)谑褂煤蟮玫结尫牛駝t可能會(huì)導(dǎo)致死鎖。
  • 使用 select 語(yǔ)句:在使用通道進(jìn)行并發(fā)操作時(shí),可以使用 select 語(yǔ)句來(lái)避免死鎖。通過(guò) select 語(yǔ)句選擇多個(gè)通道中的一個(gè)進(jìn)行操作,可以避免在某個(gè)通道被阻塞時(shí)出現(xiàn)死鎖。

發(fā)生活鎖的案例分析

1.編寫會(huì)發(fā)生活鎖的代碼:

package?main

import?(
?"fmt"
?"sync"
)

func?main()?{
?var?wg?sync.WaitGroup
?var?mu?sync.Mutex
?var?flag?bool

?wg.Add(2)

?//?goroutine?1
?go?func()?{
??//?先獲取鎖資源
??fmt.Println("goroutine?1?獲取?mu")
??mu.Lock()
??defer?mu.Unlock()

??//?然后等待?flag?變量的值變?yōu)?true
??fmt.Println("goroutine?1?等待標(biāo)志")
??for?!flag?{
???//?不斷循環(huán)等待
??}

??//?最終輸出并釋放鎖資源
??fmt.Println("goroutine?1?從等待中釋放")
??wg.Done()
?}()

?//?goroutine?2
?go?func()?{
??//?先獲取鎖資源
??fmt.Println("goroutine?2?獲取?mu")
??mu.Lock()
??defer?mu.Unlock()

??//?然后等待?flag?變量的值變?yōu)?true
??fmt.Println("GoRoutine2?等待標(biāo)志")
??for?!flag?{
???//?不斷循環(huán)等待
??}

??//?最終輸出并釋放鎖資源
??fmt.Println("GoRoutine?2?從等待中釋放")
??wg.Done()
?}()

?//?在主線程中等待?1?秒鐘,以便兩個(gè)?goroutine?開(kāi)始等待?flag?變量的值
?//?然后將?flag?變量設(shè)置為?true
?//?由于兩個(gè)?goroutine?會(huì)同時(shí)喚醒并嘗試獲取鎖資源,它們會(huì)相互等待
?//?最終導(dǎo)致了活鎖問(wèn)題,它們都無(wú)法向前推進(jìn)
?fmt.Println("主線程休眠?1?秒")
?fmt.Println("兩個(gè)goroutine都應(yīng)該等待標(biāo)志")
?flag?=?true
?wg.Wait()

?fmt.Println("所有?GoRoutines?已完成")
}

運(yùn)行和輸出:

[root@workhost temp02]# go run main.go 
主線程休眠 1 秒
兩個(gè)goroutine都應(yīng)該等待標(biāo)志
goroutine 2 獲取 mu
GoRoutine2 等待標(biāo)志
GoRoutine 2 從等待中釋放
goroutine 1 獲取 mu
goroutine 1 等待標(biāo)志
goroutine 1 從等待中釋放
所有 GoRoutines 已完成

上面的代碼存在活鎖問(wèn)題。如果兩個(gè)goroutine同時(shí)等待flag變?yōu)閠rue并且都已經(jīng)獲取了鎖資源,那么它們就會(huì)進(jìn)入一個(gè)死循環(huán)并相互等待,無(wú)法繼續(xù)向前推進(jìn)。

2.代碼改造

改造后的代碼:

package?main

import?(
?"fmt"
?"runtime"
?"sync"
)

func?main()?{
?var?wg?sync.WaitGroup
?var?mu?sync.Mutex
?var?flag?bool

?wg.Add(2)

?//?goroutine?1
?go?func()?{
??//?先獲取鎖資源
??fmt.Println("goroutine?1?獲取?mu")
??mu.Lock()
??defer?mu.Unlock()

??//?然后等待?flag?變量的值變?yōu)?true
??fmt.Println("goroutine?1?等待標(biāo)志")
??for?!flag?{
???runtime.Gosched()?//?讓出時(shí)間片
??}

??//?最終輸出并釋放鎖資源
??fmt.Println("goroutine?1?從等待中釋放")
??wg.Done()
?}()

?//?goroutine?2
?go?func()?{
??//?先獲取鎖資源
??fmt.Println("goroutine?2?獲取?mu")
??mu.Lock()
??defer?mu.Unlock()

??//?然后等待?flag?變量的值變?yōu)?true
??fmt.Println("GoRoutine2?等待標(biāo)志")
??for?!flag?{
???runtime.Gosched()?//?讓出時(shí)間片
??}

??//?最終輸出并釋放鎖資源
??fmt.Println("GoRoutine?2?從等待中釋放")
??wg.Done()
?}()

?//?在主線程中等待?1?秒鐘,以便兩個(gè)?goroutine?開(kāi)始等待?flag?變量的值
?//?然后將?flag?變量設(shè)置為?true
?//?由于兩個(gè)?goroutine?會(huì)同時(shí)喚醒并嘗試獲取鎖資源,它們會(huì)相互等待
?//?最終導(dǎo)致了活鎖問(wèn)題,它們都無(wú)法向前推進(jìn)
?fmt.Println("主線程休眠?1?秒")
?fmt.Println("兩個(gè)goroutine都應(yīng)該等待標(biāo)志")
?flag?=?true
?wg.Wait()

?fmt.Println("所有?GoRoutines?已完成")
}

改造后的代碼在等待flag變量的循環(huán)中加入了讓出時(shí)間片的函數(shù) runtime.Gosched(),這樣兩個(gè)goroutine在等待期間可以放棄時(shí)間片,以便其他goroutine可以執(zhí)行并獲得鎖資源。這種方式可以有效地減少競(jìng)爭(zhēng)程度,從而避免了活鎖問(wèn)題。

3.如何避免發(fā)生活鎖的可能性

在 Go 語(yǔ)言的并發(fā)編程中,避免活鎖的關(guān)鍵是正確地實(shí)現(xiàn)同步機(jī)制。以下是一些避免活鎖的方法:

  • 避免忙等待:使用 sync.Cond 或者 channel 等同步機(jī)制來(lái)實(shí)現(xiàn)等待。這樣避免了線程一直占用 CPU 資源而無(wú)法取得進(jìn)展的問(wèn)題。
  • 避免死鎖:死鎖往往是活鎖的前提,因此正確地使用鎖和同步機(jī)制可以避免死鎖,從而避免活鎖。
  • 減少鎖的粒度:盡可能將鎖的粒度縮小到最小范圍,避免鎖住不必要的代碼塊。
  • 采用超時(shí)機(jī)制:使用 sync.Mutex 的 TryLock() 方法或者使用 select 語(yǔ)句實(shí)現(xiàn)等待超時(shí)機(jī)制,這樣可以防止線程無(wú)限期等待。
  • 合理設(shè)計(jì)并發(fā)模型:合理設(shè)計(jì)并發(fā)模型可以避免競(jìng)爭(zhēng)和饑餓等問(wèn)題,進(jìn)而避免活鎖的發(fā)生。

以上就是Go并發(fā)編程之死鎖與活鎖的案例分析的詳細(xì)內(nèi)容,更多關(guān)于Go死鎖 活鎖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • GO語(yǔ)言獲取系統(tǒng)環(huán)境變量的方法

    GO語(yǔ)言獲取系統(tǒng)環(huán)境變量的方法

    這篇文章主要介紹了GO語(yǔ)言獲取系統(tǒng)環(huán)境變量的方法,實(shí)例分析了Getenv方法操作環(huán)境變量的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • go語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之前綴樹(shù)Trie

    go語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之前綴樹(shù)Trie

    這篇文章主要介紹了go語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之前綴樹(shù)Trie,文章圍繞主題展開(kāi)詳細(xì)內(nèi)容介紹,具有一定得參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • Golang中Delve版本太低無(wú)法Debug的問(wèn)題

    Golang中Delve版本太低無(wú)法Debug的問(wèn)題

    這篇文章主要介紹了Golang中Delve版本太低無(wú)法Debug的問(wèn)題,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • golang實(shí)現(xiàn)對(duì)JavaScript代碼混淆

    golang實(shí)現(xiàn)對(duì)JavaScript代碼混淆

    在Go語(yǔ)言中,你可以使用一些工具來(lái)混淆JavaScript代碼,一個(gè)常用的工具是Terser,它可以用于壓縮和混淆JavaScript代碼,你可以通過(guò)Go語(yǔ)言的`os/exec`包來(lái)調(diào)用Terser工具,本文給通過(guò)一個(gè)簡(jiǎn)單的示例給大家介紹一下,感興趣的朋友可以參考下
    2024-01-01
  • golang jsoniter extension 處理動(dòng)態(tài)字段的實(shí)現(xiàn)方法

    golang jsoniter extension 處理動(dòng)態(tài)字段的實(shí)現(xiàn)方法

    這篇文章主要介紹了golang jsoniter extension 處理動(dòng)態(tài)字段的實(shí)現(xiàn)方法,我們使用實(shí)例級(jí)別的 extension, 而非全局,可以針對(duì)不同業(yè)務(wù)邏輯有所區(qū)分,jsoniter 包提供了比較完善的定制能力,通過(guò)例子可以感受一下擴(kuò)展性,需要的朋友可以參考下
    2023-04-04
  • Go反射中type和kind區(qū)別比較詳析

    Go反射中type和kind區(qū)別比較詳析

    這篇文章主要給大家介紹了關(guān)于Go反射中type和kind區(qū)別比較的相關(guān)資料,Type是接口類型,Value是Struct類型,Type是類型描述,而Value是具體的值,需要的朋友可以參考下
    2023-10-10
  • golang中bufio.SplitFunc的深入理解

    golang中bufio.SplitFunc的深入理解

    這篇文章主要給大家介紹了關(guān)于golang中bufio.SplitFunc的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-10-10
  • Go/C語(yǔ)言LeetCode題解997找到小鎮(zhèn)法官

    Go/C語(yǔ)言LeetCode題解997找到小鎮(zhèn)法官

    這篇文章主要為大家介紹了Go語(yǔ)言LeetCode題解997找到小鎮(zhèn)的法官示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Go語(yǔ)言context上下文管理的使用

    Go語(yǔ)言context上下文管理的使用

    本文主要介紹了Go語(yǔ)言context上下文管理的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • go:垃圾回收GC觸發(fā)條件詳解

    go:垃圾回收GC觸發(fā)條件詳解

    這篇文章主要介紹了go:垃圾回收GC觸發(fā)條件詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04

最新評(píng)論

闽清县| 昌乐县| 黑水县| 湖口县| 遵化市| 桐庐县| 东方市| 禄劝| 吉隆县| 东海县| 来宾市| 中山市| 壤塘县| 云林县| 秦皇岛市| 浠水县| 海兴县| 闽侯县| 连平县| 台前县| 博兴县| 项城市| 永修县| 万全县| 于田县| 黔西县| 巧家县| 蓬安县| 新邵县| 洪江市| 伽师县| 浑源县| 蒲城县| 共和县| 澄江县| 奉新县| 石景山区| 岗巴县| 原阳县| 澳门| 弥勒县|