Golang 通道写入和读取问题 - golang 通道新手

问题描述 投票:0回答:1

这是 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()
}
  1. 第一个问题是没有排序,我期望输入、输出 x3,但事实并非如此。有多个“输入”和“输出”分组。但我看过其他问题,似乎只是没有按正确的顺序打印。如果我说错了请指正
  2. 第二个是只有两个出局,而应该是 3 个。
go concurrency channel waitgroup
1个回答
0
投票

以相反的顺序处理你的问题...

正如 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)

上面建议的第二个例程的更改已经负责输出接收到的值,但您可能仍然对输出感到困惑。例如,您可能会看到一个值(似乎)在发送之前就已被接收!

这有两个原因:

  1. 在建立接收 go 例程之前设置发送 go 例程

  2. 您在发送之后发出“已发送”日志,这会在发送 Goroutine 有机会发出该日志之前创建一个接收和处理消息的机会窗口

解决方案是解决这些排序问题:

  1. 首先建立你的接收者 goroutine - 即,在你启动 goroutine 并开始从中读取消息之前,不要开始向通道发送消息(在处理通道时,这并不总是必要的,但可以帮助你理解正在发生的事情)在这种情况下)

  2. 在向通道发送消息之前

    向控制台发出“正在发送”消息;这消除了在发出记录的输出之前接收和处理发送的消息的可能性

  3. 这应该会产生与此类似的结果:

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

中找到可运行的解决方案

© www.soinside.com 2019 - 2024. All rights reserved.