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

關于Golang中for-loop與goroutine的問題詳解

 更新時間:2017年09月04日 08:43:24   作者:寇池濱  
這篇文章主要給大家介紹了關于Golang中for-loop與goroutine問題的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用golang具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。

背景

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

參見如下代碼:

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,因此最高下標為2,在非并行編程中代碼中的for-loop應該是很直觀的,我當時并沒有意識到有什么問題??墒窃谡{試過程中,一直在報 index out of bounds 錯誤。調試信息顯示i的值為3,當時就一直想不明白循環(huán)條件明明是 i < 2,怎么會變成3呢。

分析

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

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

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

或者使用閉包(closure):

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

這里的問題在于 val 實際上是一個遍歷了切片中所有數(shù)據(jù)的單一變量。由于閉包只是綁定到這個 val 變量上,因此極有可能上面的代碼的運行結果是所有 goroutine 都輸出了切片的最后一個元素。這是因為很有可能當 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 都會被獨立計算并保存到 goroutine 的棧中,從而得到預期的結果。

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

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

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

server := i

總結

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

相關文章

  • go 原生http web 服務跨域restful api的寫法介紹

    go 原生http web 服務跨域restful api的寫法介紹

    這篇文章主要介紹了go 原生http web 服務跨域restful api的寫法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • go語言簡單的處理http請求的函數(shù)實例

    go語言簡單的處理http請求的函數(shù)實例

    這篇文章主要介紹了go語言簡單的處理http請求的函數(shù),實例分析了Go語言處理http請求的技巧,需要的朋友可以參考下
    2015-03-03
  • 五步讓你成為GO 語言高手

    五步讓你成為GO 語言高手

    本文給大家介紹的這里是GO程序員的五個進化階段,從最開始的菜逼到最終的布道者,附上各種示例,一步步走向大神之路,推薦給小伙伴們,有需要的朋友可以參考下
    2015-03-03
  • golang rate令牌桶源碼分析實現(xiàn)方式

    golang rate令牌桶源碼分析實現(xiàn)方式

    這篇文章主要介紹了golang rate令牌桶源碼分析實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Go語言基于HTTP的內存緩存服務的實現(xiàn)

    Go語言基于HTTP的內存緩存服務的實現(xiàn)

    這篇文章主要介紹了Go語言基于HTTP的內存緩存服務,本程序采用REST接口,支持設置(Set)、獲取(Get)和刪除(Del)這3個基本操作,同時還支持對緩存服務狀態(tài)進行查詢,需要的朋友可以參考下
    2022-08-08
  • Go中的Timer 和 Ticker詳解

    Go中的Timer 和 Ticker詳解

    在日常開發(fā)中,我們可能會遇到需要延遲執(zhí)行或周期性地執(zhí)行一些任務,這個時候就需要用到 Go 語言中的定時器,本文將會對這兩種定時器類型進行介紹,感興趣的朋友一起看看吧
    2024-07-07
  • 淺析Golang中類型嵌入的簡介與使用

    淺析Golang中類型嵌入的簡介與使用

    類型嵌入指的就是在一個類型的定義中嵌入了其他類型,Go?語言支持兩種類型嵌入,分別是接口類型的類型嵌入和結構體類型的類型嵌入,下面我們就來詳細一下類型嵌入的使用吧
    2023-11-11
  • golang?gorm的關系關聯(lián)實現(xiàn)示例

    golang?gorm的關系關聯(lián)實現(xiàn)示例

    這篇文章主要為大家介紹了golang?gorm的關系關聯(lián)實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • golang中結構體嵌套接口的實現(xiàn)

    golang中結構體嵌套接口的實現(xiàn)

    本文主要介紹了golang中結構體嵌套接口的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • Go語言制作svg格式樹形圖的示例代碼

    Go語言制作svg格式樹形圖的示例代碼

    SVG是可伸縮矢量圖形?(Scalable?Vector?Graphics),于2003年1月14日成為?W3C?推薦標準。本文將利用Go語言實現(xiàn)制作svg格式樹形圖,感興趣的可以了解一下
    2022-09-09

最新評論