濮阳杆衣贸易有限公司

主頁 > 知識庫 > 關(guān)于Golang中for-loop與goroutine的問題詳解

關(guān)于Golang中for-loop與goroutine的問題詳解

熱門標(biāo)簽:汕頭小型外呼系統(tǒng) 黃岡人工智能電銷機(jī)器人哪個好 鄭州亮點(diǎn)科技用的什么外呼系統(tǒng) 阿里云ai電話機(jī)器人 濱州自動電銷機(jī)器人排名 惠州電銷防封電話卡 釘釘有地圖標(biāo)注功能嗎 浙江高頻外呼系統(tǒng)多少錢一個月 建造者2地圖標(biāo)注

背景

最近在學(xué)習(xí)MIT的分布式課程6.824的過程中,使用Go實(shí)現(xiàn)Raft協(xié)議時遇到了一些問題。分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧。

參見如下代碼:

for i := 0; i  len(rf.peers); i++ {
  DPrintf("i = %d", i)

  if i == rf.me {
   DPrintf("skipping myself #%d", rf.me)
   continue
  }

  go func() {
   DPrintf("len of rf.peers = %d", len(rf.peers))
   DPrintf("server #%d sending request vote to server %d", rf.me, i)
   reply := RequestVoteReply{}
   ok := rf.sendRequestVote(i, args, reply)
   if ok  reply.VoteGranted  reply.Term == rf.currentTerm {
    rf.voteCount++
    if rf.voteCount > len(rf.peers)/2 {
     rf.winElectionCh - true
    }
   }
  }()
}

其中,peers切片的長度為3,因此最高下標(biāo)為2,在非并行編程中代碼中的for-loop應(yīng)該是很直觀的,我當(dāng)時并沒有意識到有什么問題。可是在調(diào)試過程中,一直在報 index out of bounds 錯誤。調(diào)試信息顯示i的值為3,當(dāng)時就一直想不明白循環(huán)條件明明是 i 2,怎么會變成3呢。

分析

雖然不明白發(fā)生了什么,但知道應(yīng)該是循環(huán)中引入的 goroutine 導(dǎo)致的。經(jīng)過Google,發(fā)現(xiàn)Go的wiki中就有一個頁面 Common Mistake - Using goroutines on loop iterator variables 專門提到了這個問題,看來真的是很 common 啊,笑哭~

初學(xué)者經(jīng)常會使用如下代碼來并行處理數(shù)據(jù):

for val := range values {
 go val.MyMethod()
}

或者使用閉包(closure):

for val := range values {
 go func() {
  fmt.Println(val)
 }()
}

這里的問題在于 val 實(shí)際上是一個遍歷了切片中所有數(shù)據(jù)的單一變量。由于閉包只是綁定到這個 val 變量上,因此極有可能上面的代碼的運(yùn)行結(jié)果是所有 goroutine 都輸出了切片的最后一個元素。這是因?yàn)楹苡锌赡墚?dāng) for-loop 執(zhí)行完之后 goroutine 才開始執(zhí)行,這個時候 val 的值指向切片中最后一個元素。

The val variable in the above loops is actually a single variable that takes on the value of each slice element. Because the closures are all only bound to that one variable, there is a very good chance that when you run this code you will see the last element printed for every iteration instead of each value in sequence, because the goroutines will probably not begin executing until after the loop.

解決方法

以上代碼正確的寫法為:

for val := range values {
 go func(val interface{}) {
  fmt.Println(val)
 }(val)
}

在這里將 val 作為一個參數(shù)傳入 goroutine 中,每個 val 都會被獨(dú)立計算并保存到 goroutine 的棧中,從而得到預(yù)期的結(jié)果。

另一種方法是在循環(huán)內(nèi)定義新的變量,由于在循環(huán)內(nèi)定義的變量在循環(huán)遍歷的過程中是不共享的,因此也可以達(dá)到同樣的效果:

for i := range valslice {
 val := valslice[i]
 go func() {
  fmt.Println(val)
 }()
}

對于文章開頭提到的那個問題,最簡單的解決方案就是在循環(huán)內(nèi)加一個臨時變量,并將后面 goroutine 內(nèi)的 i 都替換為這個臨時變量即可:

server := i

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • 解決Golang中g(shù)oroutine執(zhí)行速度的問題
  • golang goroutine順序輸出方式
  • golang gin 框架 異步同步 goroutine 并發(fā)操作
  • GOLANG使用Context管理關(guān)聯(lián)goroutine的方法
  • Golang 探索對Goroutine的控制方法(詳解)
  • Golang 語言控制并發(fā) Goroutine的方法

標(biāo)簽:泰安 東營 阿壩 瀘州 滄州 昭通 駐馬店 晉中

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《關(guān)于Golang中for-loop與goroutine的問題詳解》,本文關(guān)鍵詞  關(guān)于,Golang,中,for-loop,與,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《關(guān)于Golang中for-loop與goroutine的問題詳解》相關(guān)的同類信息!
  • 本頁收集關(guān)于關(guān)于Golang中for-loop與goroutine的問題詳解的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    家居| 洪泽县| 翁牛特旗| 太湖县| 上饶市| 新巴尔虎右旗| 进贤县| 乌兰察布市| 望都县| 那曲县| 胶州市| 马边| 西峡县| 南通市| 涿州市| 蕲春县| 噶尔县| 惠安县| 沾益县| 辽宁省| 衢州市| 衡阳县| 陇西县| 新巴尔虎左旗| 伽师县| 辛集市| 吉安市| 兴和县| 林西县| 从江县| 芦山县| 江永县| 乌拉特后旗| 桦川县| 三台县| 克什克腾旗| 抚宁县| 双峰县| 威信县| 报价| 灵丘县|