Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select within goroutine evaluates every other statement

Tags:

concurrency

go

Playing around with Go's channels and routines I have come across a peculiar behaviour I was hoping somebody could explain.

Below is a short program that is supposed to print a couple strings to stdout, by sending the strings through a channel to a "listener" (the select statement) running in a separate goroutine.

package main

import (
    "fmt"
    "time"
)

func main() {
    a := make(chan string)

    go func() {
        for {
            select {
            case <-a:
                fmt.Print(<-a)
            }
        }
    }()

    a <- "Hello1\n"
    a <- "Hello2\n"
    a <- "Hello3\n"
    a <- "Hello4\n"        
    time.Sleep(time.Second) 
}

Using

go func() {
    for s := range a {
        fmt.Print(s)
    }
}()

// or even simpler

go func() {
    for {
        fmt.Print(<-a)
    }
}()

works as expected. However, running the uppermost snippet with the select statement produces the following output:

Hello2
Hello4

i.e. only every other statement is printed. What kind of sorcery is this?

like image 936
Milo Wielondek Avatar asked Mar 23 '13 22:03

Milo Wielondek


1 Answers

In the uppermost snippet, you're pulling two values from the channel for each loop. One in the select statement and one in the print statement.

Change

        select {
        case <-a:
            fmt.Print(<-a)

To

        select {
        case val := <-a:
            fmt.Print(val)

http://play.golang.org/p/KIADcwkoKs

like image 145
Daniel Avatar answered Oct 02 '22 04:10

Daniel