这是 golang 通道的简单生产者消费者问题。我想将一些东西放入in通道,然后out将其写在控制台上。
package main
import (
"fmt"
"sync"
"time"
)
func main() {
chIn := make(chan string)
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 3; i++ {
chIn <- "in"
fmt.Println("in")
}
close(chIn)
}()
go func() {
defer wg.Done()
for range chIn {
<-chIn
fmt.Println("out")
}
}()
wg.Wait()
}
以相反的顺序处理你的问题...
正如 Burak Serdar 在他们的评论中提到的,输出数量与输入数量的差异是由于您在第二个 goroutine 中从通道中进行了额外的、不必要的读取而引起的:
这个:
for range chIn {
<-chIn
fmt.Println("out")
}
应该更像是:
for in := range chIn {
fmt.Println(in)
}
这将处理不同数量的输出与输入。
要理解“排序”的问题,发送有助于识别发送顺序的值并打印这些值以便您可以看到它们的接收顺序可能会有所帮助。
因此,发送:
chIn <- fmt.Sprintf("#%d", i+1)
fmt.Printf("sent #%d\n", i+1)
上面建议的第二个例程的更改已经负责输出接收到的值,但您可能仍然对输出感到困惑。例如,您可能会看到一个值(似乎)在发送之前就已被接收!
这有两个原因:
在建立接收 go 例程之前设置发送 go 例程
您在发送之后发出“已发送”日志,这会在发送 Goroutine 有机会发出该日志之前创建一个接收和处理消息的机会窗口
向控制台发出“正在发送”消息;这消除了在发出记录的输出之前接收和处理发送的消息的可能性
package main
import (
"fmt"
"sync"
)
func main() {
chIn := make(chan string)
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
for in := range chIn {
fmt.Printf("rcvd: %s\n", in)
}
}()
go func() {
defer wg.Done()
for i := 0; i < 3; i++ {
fmt.Printf("sending #%d\n", i+1)
chIn <- fmt.Sprintf("#%d", i+1)
}
close(chIn)
}()
wg.Wait()
}
输出仍将由交错的发送和接收日志组成,但排序现在应该是合理的,产生类似于以下内容的内容:
sending #1
sending #2
rcvd: #1
rcvd: #2
sending #3
rcvd: #3
可以在这个Playground