【问题标题】:Go channel takes each letter as string instead of the whole stringGo 通道将每个字母作为字符串而不是整个字符串
【发布时间】:2016-09-27 22:40:36
【问题描述】:

我正在创建一个接受字符串值的简单通道。但显然我正在推动字符串中的每个字母,而不是每个循环中的整个字符串。

我可能遗漏了一些非常基本的东西。我做错了什么?

https://play.golang.org/p/-6E-f7ALbD

代码:

func doStuff(s string, ch chan string) {
    ch <- s
}

func main() {
    c := make(chan string)
    loops := [5]int{1, 2, 3, 4, 5}

    for i := 0; i < len(loops); i++ {
        go doStuff("helloooo", c)
    }

    results := <-c

    fmt.Println("channel size = ", len(results))

    // print the items in channel
    for _, r := range results {
        fmt.Println(string(r))
    }
}

【问题讨论】:

    标签: string go channel


    【解决方案1】:

    您的代码在频道上正确发送strings:

    func doStuff(s string, ch chan string){
        ch <- s
    }
    

    问题出在接收端:

    results := <- c
    
    fmt.Println("channel size = ", len(results))
    
    // print the items in channel
    for _,r := range results {
      fmt.Println(string(r))
    }
    

    results 将是从通道接收到的单个 值(在其上发送的第一个值)。然后你打印这个string的长度。

    然后您使用循环在其runes 上的for range 循环此字符串 (results),然后打印它们。

    你想要的是循环通道的值:

    // print the items in channel
    for s := range c {
        fmt.Println(s)
    }
    

    这在运行时会导致运行时恐慌:

    fatal error: all goroutines are asleep - deadlock!
    

    因为您永远不会关闭频道,并且频道上的for range 会一直运行直到频道关闭。所以你必须在某个时候关闭频道。

    例如让我们等待 1 秒,然后关闭它:

    go func() {
        time.Sleep(time.Second)
        close(c)
    }()
    

    这样您的应用将在 1 秒后运行并退出。在 Go Playground 上试试吧。

    另一个更好的解决方案是使用sync.WaitGroup:它会等待所有 goroutine 完成工作(在通道上发送值),然后关闭通道(因此没有不必要的等待/延迟)。

    var wg = sync.WaitGroup{}
    
    func doStuff(s string, ch chan string) {
        ch <- s
        wg.Done()
    }
    
    // And in main():
    for i := 0; i < len(loops); i++ {
        wg.Add(1)
        go doStuff("helloooo", c)
    }
    go func() {
        wg.Wait()
        close(c)
    }()
    

    Go Playground 上试试这个。

    注意事项:

    要重复 5 次,你不需要那个丑陋的 loops 数组。只需这样做:

    for i := 0; i < 5; i++ {
        // Do something
    }
    

    【讨论】:

    • 感谢您提供详细信息。
    【解决方案2】:

    你得到字母而不是字符串的原因是你将通道结果分配给一个变量并迭代分配给这个变量的通道结果,在你的情况下是一个字符串,在 Go 中你可以使用 for range 循环遍历字符串以获取符文。

    您可以简单地打印通道,而无需遍历通道结果。

    package main
    
    import (
        "fmt"
    )
    
    func doStuff(s string, ch chan string){
        ch <- s
    }
    
    func main() {
        c := make(chan string)
        loops := [5]int{1,2,3,4,5}
    
        for i := 0; i < len(loops) ; i++ {
           go doStuff("helloooo", c)    
        }
    
        results := <- c 
        fmt.Println("channel size = ", len(results))
        fmt.Println(results) // will print helloooo
    }
    

    【讨论】:

      猜你喜欢
      • 2012-07-30
      • 1970-01-01
      • 2018-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      相关资源
      最近更新 更多