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
这是因为 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 更多时间执行。但这并不是可靠的同步方式,只是恰好避免了程序过早退出。

