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

Go語(yǔ)言單線程運(yùn)行也會(huì)有的并發(fā)問(wèn)題解析

 更新時(shí)間:2023年12月20日 09:22:41   作者:晁岳攀(鳥窩)?鳥窩聊技術(shù)  
這篇文章主要為大家介紹了Go語(yǔ)言單線程運(yùn)行的并發(fā)問(wèn)題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

Go單線程多goroutine訪問(wèn)一個(gè)map會(huì)遇到并發(fā)讀寫panic么?

一個(gè) Go 大佬群中嚴(yán)肅的討論了一個(gè)問(wèn)題:Go 程序單線程多 goroutine 訪問(wèn)一個(gè) map 會(huì)遇到并發(fā)讀寫 panic 么?

答案是肯定的,因?yàn)槌霈F(xiàn)了這個(gè)問(wèn)題所以大家才在群中討論。

為什么呢?因?yàn)閱尉€程意味著并行單元只有一個(gè)(多線程也可能并行單元只有一個(gè)),但是多 goroutine 意味著并發(fā)單元有多個(gè),如果并發(fā)單元同時(shí)執(zhí)行,即使是單線程,可能就會(huì)產(chǎn)生數(shù)據(jù)競(jìng)爭(zhēng)的問(wèn)題,除非這些 goroutine 是順序執(zhí)行的。

舉一個(gè)例子哈:

func TestCounter() {
    runtime.GOMAXPROCS(1)
 var counter int
 var wg sync.WaitGroup
 wg.Add(10)
 for i := 0; i < 10; i++ {
  i := i
  go func() {
   fmt.Printf("start task#%d, counter: %d\n", i, counter)
   for j := 0; j < 10_0000; j++ {
    counter++
   }
   fmt.Printf("end task#%d, counter: %d\n", i, counter)
   wg.Done()
  }()
 }
 wg.Wait()
 fmt.Println(counter)
}

這段測(cè)試代碼是啟動(dòng) 10 個(gè) goroutine 對(duì)計(jì)數(shù)器加一,每個(gè) goroutine 負(fù)責(zé)加 10 萬(wàn)次。在我的 MBP m1 筆記本上,每次的結(jié)果都是 100 萬(wàn),符合期望。如果你運(yùn)行這段代碼,會(huì)發(fā)現(xiàn) goroutine 其實(shí)是一個(gè)一個(gè)串行執(zhí)行的(9->0->1->2->3->4->5->6->7->8,當(dāng)然可能在你的機(jī)器上不是這樣的),如果是串行執(zhí)行,不會(huì)有并發(fā)問(wèn)題:

start task#9, counter: 0
end task#9, counter: 100000
start task#0, counter: 100000
end task#0, counter: 200000
start task#1, counter: 200000
end task#1, counter: 300000
start task#2, counter: 300000
end task#2, counter: 400000
start task#3, counter: 400000
end task#3, counter: 500000
start task#4, counter: 500000
end task#4, counter: 600000
start task#5, counter: 600000
end task#5, counter: 700000
start task#6, counter: 700000
end task#6, counter: 800000
start task#7, counter: 800000
end task#7, counter: 900000
start task#8, counter: 900000
end task#8, counter: 1000000
1000000

插入runtime.Gosched()

為了制造點(diǎn)緊張氣氛,我將代碼改寫成下面這樣子,將counter++三條指令明顯寫成三條語(yǔ)句,并在中間插入runtime.Gosched(),故意給其它 goroutine 的執(zhí)行制造機(jī)會(huì):

func TestCounter2() {
    runtime.GOMAXPROCS(1)
 var counter int
 var wg sync.WaitGroup
 wg.Add(10)
 for i := 0; i < 10; i++ {
  i := i
  go func() {
   fmt.Printf("start task#%d, counter: %d\n", i, counter)
   for j := 0; j < 10_0000; j++ {
    temp := counter
    runtime.Gosched()
    temp = temp + 1
    counter = temp
   }
   fmt.Printf("end task#%d, counter: %d\n", i, counter)
   wg.Done()
  }()
 }
 wg.Wait()
 fmt.Println(counter)
}

運(yùn)行這段代碼,你就會(huì)明顯看到數(shù)據(jù)不一致的效果,即使是單個(gè)線程運(yùn)行 goroutine,也出現(xiàn)了數(shù)據(jù)競(jìng)爭(zhēng)的問(wèn)題:

start task#9, counter: 0
start task#0, counter: 0
start task#1, counter: 0
start task#2, counter: 0
start task#3, counter: 0
start task#4, counter: 0
start task#5, counter: 0
start task#6, counter: 0
start task#7, counter: 0
start task#8, counter: 0
end task#9, counter: 100000
end task#1, counter: 100000
end task#3, counter: 100000
end task#2, counter: 100000
end task#5, counter: 100000
end task#0, counter: 100000
end task#4, counter: 100000
end task#6, counter: 100000
end task#7, counter: 100000
end task#8, counter: 100000
100000

這個(gè)結(jié)果非常離譜,期望 100 萬(wàn),最后只有 10 萬(wàn)。

訪問(wèn)同一個(gè) map對(duì)象也有可能出現(xiàn)并發(fā)bug

因?yàn)閱蝹€(gè)線程運(yùn)行多個(gè) goroutine 會(huì)有數(shù)據(jù)競(jìng)爭(zhēng)的問(wèn)題,所以訪問(wèn)同一個(gè) map 對(duì)象也有可能出現(xiàn)并發(fā) bug,比如下面的代碼,10 個(gè) goroutine 并發(fā)的寫同一個(gè) map:

func TestMap() {
 var m = make(map[int]int)
 var wg sync.WaitGroup
 wg.Add(10)
 for i := 0; i < 10; i++ {
  i := i
  go func() {
   fmt.Printf("start map task#%d, m: %v\n", i, len(m))
   for j := 0; j < 10_0000; j++ {
    m[j] = i*10_0000 + j
   }
   fmt.Printf("end map task#%d, m: %v\n", i, len(m))
   wg.Done()
  }()
 }
 wg.Wait()
}

大概率會(huì)出現(xiàn) panic:

start map task#9, m: 0
start map task#0, m: 49152
fatal error: concurrent map writes
goroutine 41 [running]:
main.TestMap.func1()
 /Users/chaoyuepan/study/single_thread/main.go:72 +0xcc
created by main.TestMap in goroutine 1
 /Users/chaoyuepan/study/single_thread/main.go:69 +0x4c
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0x140000021a0?)
 /usr/local/go/src/runtime/sema.go:62 +0x2c
sync.(*WaitGroup).Wait(0x1400000e1d0)
 /usr/local/go/src/sync/waitgroup.go:116 +0x74
main.TestMap()
 /Users/chaoyuepan/study/single_thread/main.go:79 +0xb8
main.main()
 /Users/chaoyuepan/study/single_thread/main.go:15 +0x2c

以上就是Go語(yǔ)言單線程運(yùn)行的并發(fā)問(wèn)題解析的詳細(xì)內(nèi)容,更多關(guān)于Go單線程運(yùn)行并發(fā)問(wèn)題的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語(yǔ)言二進(jìn)制文件的讀寫操作

    Go語(yǔ)言二進(jìn)制文件的讀寫操作

    本文主要介紹了Go語(yǔ)言二進(jìn)制文件的讀寫操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • go格式“占位符”輸入輸出 類似python的input

    go格式“占位符”輸入輸出 類似python的input

    這篇文章主要介紹了go格式“占位符”, 輸入輸出,類似python的input,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-04-04
  • 使用Go構(gòu)建一款靜態(tài)分析工具Owl詳解

    使用Go構(gòu)建一款靜態(tài)分析工具Owl詳解

    Owl是一款開源項(xiàng)目依賴分析工具,可以快速在指定的項(xiàng)目目錄下查找符合某些特征的源代碼文件或者依賴文件,這篇文章主要介紹了使用Go構(gòu)建一款靜態(tài)分析工具,需要的朋友可以參考下
    2022-06-06
  • go語(yǔ)言按顯示長(zhǎng)度截取字符串的方法

    go語(yǔ)言按顯示長(zhǎng)度截取字符串的方法

    這篇文章主要介紹了go語(yǔ)言按顯示長(zhǎng)度截取字符串的方法,涉及Go語(yǔ)言操作字符串的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • Golang服務(wù)的請(qǐng)求調(diào)度的實(shí)現(xiàn)

    Golang服務(wù)的請(qǐng)求調(diào)度的實(shí)現(xiàn)

    Golang服務(wù)請(qǐng)求調(diào)度是一種使用Go語(yǔ)言實(shí)現(xiàn)的服務(wù)請(qǐng)求管理方法,本文主要介紹了Golang服務(wù)的請(qǐng)求調(diào)度的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • Golang編程實(shí)現(xiàn)刪除字符串中出現(xiàn)次數(shù)最少字符的方法

    Golang編程實(shí)現(xiàn)刪除字符串中出現(xiàn)次數(shù)最少字符的方法

    這篇文章主要介紹了Golang編程實(shí)現(xiàn)刪除字符串中出現(xiàn)次數(shù)最少字符的方法,涉及Go語(yǔ)言字符串遍歷與運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下
    2017-01-01
  • Go-家庭收支記賬軟件項(xiàng)目實(shí)現(xiàn)

    Go-家庭收支記賬軟件項(xiàng)目實(shí)現(xiàn)

    這篇文章主要介紹了Go-家庭收支記賬軟件項(xiàng)目實(shí)現(xiàn),本文章內(nèi)容詳細(xì),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,需要的朋友可以參考下
    2023-01-01
  • Go語(yǔ)言通過(guò)chan進(jìn)行數(shù)據(jù)傳遞的方法詳解

    Go語(yǔ)言通過(guò)chan進(jìn)行數(shù)據(jù)傳遞的方法詳解

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言如何通過(guò)chan進(jìn)行數(shù)據(jù)傳遞的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-06-06
  • Go流程控制代碼詳解

    Go流程控制代碼詳解

    這篇文章主要詳細(xì)介紹了Go流程控制,文章通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下
    2023-04-04
  • Golang中自定義json序列化時(shí)間格式的示例代碼

    Golang中自定義json序列化時(shí)間格式的示例代碼

    Go語(yǔ)言作為一個(gè)由Google開發(fā),號(hào)稱互聯(lián)網(wǎng)的C語(yǔ)言的語(yǔ)言,自然也對(duì)JSON格式支持很好,下面這篇文章主要介紹了關(guān)于Golang中自定義json序列化時(shí)間格式的相關(guān)內(nèi)容,下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧
    2024-08-08

最新評(píng)論

衡阳县| 司法| 彰武县| 井研县| 西林县| 玉屏| 和静县| 西吉县| 巩留县| 涞水县| 呼伦贝尔市| 祥云县| 云南省| 蓬安县| 遂昌县| 丰原市| 萨嘎县| 康定县| 台前县| 乡宁县| 越西县| 凤城市| 泸州市| 娄烦县| 长沙市| 临城县| 汝南县| 玛纳斯县| 大余县| 寿阳县| 新乡市| 临夏县| 邵阳市| 绿春县| 巢湖市| 尤溪县| 阿克| 鄂托克旗| 察雅县| 罗江县| 安宁市|