【问题标题】:Select within goroutine evaluates every other statement在 goroutine 中选择会评估所有其他语句
【发布时间】:2013-03-13 15:16:04
【问题描述】:

在玩 Go 的频道和例程时,我遇到了一种奇怪的行为,我希望有人能解释一下。

下面是一个简短的程序,它应该通过通道将字符串发送到在单独的 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 语句运行最上面的 sn-p 会产生以下输出:

Hello2
Hello4

即仅打印所有其他语句。这是什么魔法?

【问题讨论】:

    标签: concurrency go


    【解决方案1】:
    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) 
    }
    

    【讨论】:

      【解决方案2】:
      <-a
      

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

      试试

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

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

      【讨论】:

        【解决方案3】:

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

        改变

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

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

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

        【讨论】:

        • 谢谢,有道理。我会试一试;)
        猜你喜欢
        • 1970-01-01
        • 2019-03-06
        • 1970-01-01
        • 2019-02-20
        • 2010-10-03
        • 1970-01-01
        • 2023-01-28
        • 1970-01-01
        相关资源
        最近更新 更多