softshipper
softshipper

Reputation: 34099

After loop a channel with range app break

I have a problem, that my application is not going to reach the next statement after loop over a channel. To clarify, what I mean, look at the following code snippet.

func CreateAccount(name, email, password string) (string, string) {

    validation := make(chan error)
    errColl := make([]error, 3, 3)
    iterator := 0

    go func() {
        nameErr := IsNameValid(name)
        validation <- nameErr
    }()

    go func() {
        emailErr := IsEmailValid(email)
        validation <- emailErr

    }()

    go func() {
        passwordErr := IsPasswordValid(password)
        validation <- passwordErr
    }()

    for err := range validation {
        errColl[iterator] = err
        iterator++
    }
    fmt.Println("Hello")


    return "hello", "dude"

}

That is my create account function. After three goroutine, i make a loop over channel validation. After loop is done, the statement

fmt.Println("Hello)

is never going the execute. But when I change the function like this.

func CreateAccount(name, email, password string) (string, string) {

    validation := make(chan error)
    errColl := make([]error, 3, 3)
    //iterator := 0

    go func() {
        nameErr := IsNameValid(name)
        validation <- nameErr
    }()

    go func() {
        emailErr := IsEmailValid(email)
        validation <- emailErr

    }()

    go func() {
        passwordErr := IsPasswordValid(password)
        validation <- passwordErr
    }()

    errColl[0] = <-validation
    errColl[1] = <-validation
    errColl[2] = <-validation
    close(validation)
    fmt.Println("Hello")

    return "hello", "dude"

}

Hello is going to printed out and plus I got the return value.
What do I wrong in the first code snippet?

Upvotes: 0

Views: 1368

Answers (2)

OneOfOne
OneOfOne

Reputation: 99351

Like @peterSO said, you didn't close the channel, the proper way for that pattern is to use a sync.WaitGroup:

func CreateAccount(name, email, password string) (string, string) {
    var wg sync.WaitGroup
    validation := make(chan error, 3)
    errColl := make([]error, 3)

    wg.Add(3)
    go func() {
        nameErr := IsNameValid(name)
        validation <- nameErr
        wg.Done()
    }()

    go func() {
        emailErr := IsEmailValid(email)
        validation <- emailErr
        wg.Done()

    }()

    go func() {
        passwordErr := IsPasswordValid(password)
        validation <- passwordErr
        wg.Done()
    }()
    wg.Wait()
    for i := range errColl {
        errColl[i] = <-validation
    }

    return "hello", "dude"

}

Upvotes: 4

peterSO
peterSO

Reputation: 166815

The validation channel is never closed.

for err := range validation {
    errColl[iterator] = err
    iterator++
}

The Go Programming Language Specification

For statements

A "for" statement with a "range" clause iterates through all entries of an array, slice, string or map, or values received on a channel.

For channels, the iteration values produced are the successive values sent on the channel until the channel is closed.

Upvotes: 7

Related Questions