Golang中为什么只显示一个通道值?

Golang中为什么只显示一个通道值? 我发现了这段代码:

package main
 
import "fmt"
 
func greet(c chan string) {
    fmt.Println(<-c) // for John
    fmt.Println(<-c) // for Mike
}
 
func main() {
 
    c := make(chan string)
 
    go greet(c)
    c <- "John"
 
    c <- "Mike"
 
    //close(c) // closing channel
 
}

输出结果中只有"John",没有"Mike"。而如果我在greet函数中再写一个第三个fmt.Println(<-c),并像c <- “Adam"这样发送第三个值,输出结果就会是"John”、“Mike"和"Adam”。为什么会这样?


更多关于Golang中为什么只显示一个通道值?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

这是因为 main() 函数在两个 fmt.Println 调用完成之前就退出了。为了说明这一点,可以在 c <- "Mike" 之后添加 time.Sleep(20 * time.Millisecond) 或任意一段时间的延迟。这将给 greet 函数足够的时间来打印所有值。

在处理并发时,你需要某种机制来同步/阻塞,直到你的并发代码有时间执行。查看 sync.WaitGroup 以了解并发任务的示例,其中主线程会阻塞直到所有任务完成。其他有用的链接:

上面传入 done chan bool 的通道同步模式是非常标准的,我在很多地方都见过这种用法。

更多关于Golang中为什么只显示一个通道值?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是因为你的主 goroutine 在发送完第二个值后立即结束,导致程序退出,而 greet goroutine 可能没有足够的时间接收第二个值。

当主 goroutine 结束时,整个程序会终止,即使其他 goroutine 还在运行。在你的代码中:

func main() {
    c := make(chan string)
    go greet(c)  // 启动 goroutine
    c <- "John"  // 发送第一个值(阻塞直到被接收)
    c <- "Mike"  // 发送第二个值(阻塞直到被接收)
    // 程序立即结束
}

实际上,这段代码存在数据竞争。正确的做法是使用同步机制确保所有值都被接收。以下是几种解决方案:

方案1:使用缓冲通道

func main() {
    c := make(chan string, 2) // 缓冲大小为2
    go greet(c)
    c <- "John"
    c <- "Mike"
    // 等待goroutine完成
    time.Sleep(time.Millisecond * 100)
}

方案2:使用WaitGroup等待goroutine完成

package main

import (
    "fmt"
    "sync"
)

func greet(c chan string, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Println(<-c)
    fmt.Println(<-c)
}

func main() {
    var wg sync.WaitGroup
    c := make(chan string)
    
    wg.Add(1)
    go greet(c, &wg)
    
    c <- "John"
    c <- "Mike"
    
    wg.Wait() // 等待goroutine完成
}

方案3:使用done通道同步

package main

import "fmt"

func greet(c chan string, done chan bool) {
    fmt.Println(<-c)
    fmt.Println(<-c)
    done <- true
}

func main() {
    c := make(chan string)
    done := make(chan bool)
    
    go greet(c, done)
    
    c <- "John"
    c <- "Mike"
    
    <-done // 等待greet完成
}

在你的原始代码中,当添加第三个值时程序能正常工作的原因是:发送第三个值 c <- "Adam" 会阻塞主 goroutine,给 greet goroutine 更多时间执行。但这并不是可靠的同步方式,只是恰好避免了程序过早退出。

回到顶部