Problems of For-loop and Goroutine in Golang

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

00. Background

Recently, in the course of studying the MIT distributed course 6.824, there were some problems with go implementation of the raft protocol. See the following code:

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                }            }        }()}

Where the length of the peers slice is 3, so the highest subscript is 2, in the non-parallel programming code in the For-loop should be very intuitive, I was not aware of the problem. However, during the debugging process, the index out of bounds error has been reported. The debug message shows that I has a value of 3, and I was wondering what the loop condition was i < 2 , and how it became 3.

01. Investigation

Although I do not understand what happened, I know it should be caused by the goroutine introduced in the loop. After Google, found that go Wiki has a page Common mistake-using goroutines on loop iterator variables specifically mentioned this problem, it seems really very Common ah, laugh cry ~

Beginners often use the following code to process data in parallel:

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

Or use closures (closure):

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

The problem here is that Val is actually a single variable that traverses all the data in the slice. Since closures are only bound to this Val variable, it is very likely that the above code will run with the result that all goroutine output the last element of the slice. This is because it is likely that goroutine will not begin execution until For-loop executes, and this time Val's value points to the last element in the slice.

The Val variable in the above loops are actually a single variable this takes on the value of each slice element. Because The closures is all bound to that one variable, there was a very good chance that's when you run this code would see the last element printed for every iteration instead of each value in sequence, because the Goroutines would proba Bly not begin executing until after the loop.

02. Workaround

The code above is correctly worded as:

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

Here Val is passed as a parameter to the Goroutine, and each Val is computed independently and saved to the Goroutine stack, resulting in the desired result.

Another way is to define a new variable within the loop, because the variables defined within the loop are not shared during the loop traversal, so the same effect can be achieved:

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

The simplest solution to the problem mentioned at the beginning of the article is to add a temporary variable within the loop and replace the I in the goroutine with this temporary variable:

server :=  i

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.