在goroutine中选择评估每个其他语句

时间:2013-03-23 22:26:40

标签: concurrency go

玩Go的频道和惯例我遇到了一种特殊的行为,我希望有人可以解释。

下面是一个简短的程序,它应该通过一个通道将字符串发送给一个"监听器"来将一些字符串打印到stdout。 (select语句)在单独的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) 
}

使用

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

// or even simpler

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

按预期工作。但是,使用select语句运行最上面的代码段会产生以下输出:

Hello2
Hello4

即。只打印其他所有声明。这是什么样的巫术?

3 个答案:

答案 0 :(得分:12)

在最上面的代码段中,您为每个循环从通道中提取两个值。一个在select语句中,一个在print语句中。

更改

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

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

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

答案 1 :(得分:7)

<-a

破坏性地从频道中获取值。因此,在您的代码中,您将获得两个值,一个在select语句中,另一个用于打印。在select语句中收到的那个没有绑定到任何变量,因此丢失了。

尝试

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

相反,只获取一个值,将其绑定到变量val,然后将其打印出来。

答案 2 :(得分:0)

package main

import (
    "fmt"
    "time"
)

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

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

    a <- "Hello1\n"
    a <- "Hello2\n"
    a <- "Hello3\n"
    a <- "Hello4\n"

    time.Sleep(5*time.Second) 
}