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

huangapple go评论86阅读模式
英文:

Select within goroutine evaluates every other statement

问题

使用Go的通道和协程进行实验时,我遇到了一种奇怪的行为,希望有人能解释一下。

下面是一个简短的程序,它应该通过将字符串通过通道发送到一个“监听器”(select语句)在单独的goroutine中运行来打印一些字符串到stdout。

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

// 或者更简单的方式

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

按预期工作。然而,使用带有select语句的最上面的代码片段会产生以下输出:

Hello2
Hello4

也就是说,只有每隔一个语句才会被打印出来。这是什么魔法?

英文:

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 (
    &quot;fmt&quot;
    &quot;time&quot;
)

func main() {
    a := make(chan string)
         
    go func() {
        for {
            select {
            case &lt;-a:
                fmt.Print(&lt;-a)
            }
        }
    }()
    
    a &lt;- &quot;Hello1\n&quot;
    a &lt;- &quot;Hello2\n&quot;
    a &lt;- &quot;Hello3\n&quot;
    a &lt;- &quot;Hello4\n&quot;        
    time.Sleep(time.Second) 
}

Using

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

// or even simpler

go func() {
    for {
        fmt.Print(&lt;-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?

答案1

得分: 12

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

        select {
        case &lt;-a:
            fmt.Print(&lt;-a)

改为

        select {
        case val := &lt;-a:
            fmt.Print(val)
英文:

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 &lt;-a:
            fmt.Print(&lt;-a)

To

        select {
        case val := &lt;-a:
            fmt.Print(val)

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

答案2

得分: 7

<-a
从通道中获取一个值,具有破坏性。所以在你的代码中,你得到了两个值,一个在select语句中,一个用于打印。在select语句中接收到的值没有绑定到任何变量,因此丢失了。

尝试使用以下代码:

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

来获取一个值,将其绑定到变量val,并打印出来。

英文:
&lt;-a

gets a value from the channel, destructively. So in your code you get two values, one in the select statement, and one to print. The one received in the select statement is not bound to any variable, and is therefore lost.

Try

select {
    case val := &lt;-a:
        fmt.Print(val)

instead, to get only one value, bind it to variable val, and print it out.

答案3

得分: 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) 
}
英文:
package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

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

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

    a &lt;- &quot;Hello1\n&quot;
    a &lt;- &quot;Hello2\n&quot;
    a &lt;- &quot;Hello3\n&quot;
    a &lt;- &quot;Hello4\n&quot;
        
    time.Sleep(5*time.Second) 
}

huangapple
  • 本文由 发表于 2013年3月24日 06:26:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/15592815.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定