Go通道未接收/打印发送到通道的最后一个值

Go通道未接收/打印发送到通道的最后一个值,go,channel,goroutine,Go,Channel,Goroutine,下面是一段代码,它在推送到通道时输出整数列表。否则,select将检查并打印必要的超时消息 package main import ( "fmt" "sync" "time" ) var wg sync.WaitGroup func main() { wg.Add(1) c := make(chan int) go readFromChannel(c, time.After(time.Duration(2)*time.Second)) //

下面是一段代码,它在推送到通道时输出整数列表。否则,select将检查并打印必要的超时消息

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

func main() {
    wg.Add(1)
    c := make(chan int)

    go readFromChannel(c, time.After(time.Duration(2)*time.Second))
//  time.Sleep(time.Duration(5) * time.Second) //Talking about uncommenting this line
    c <- 10
    c <- 20
    c <- 30
    c <- 40
    c <- 50
    wg.Wait()
}

func readFromChannel(c chan int, ti <-chan time.Time) {
    defer wg.Done()
    go func() {
        for {
            select {
            case x := <-c:
                fmt.Println("Read", x)
            case t :=<-ti:
                fmt.Println("TIMED OUT with "+t.String())
            }
        }
    }()

}
但当我取消注释代码中提到的使主例程休眠5秒的行(注释/行号16)时,输出更改为:

TIMED OUT with 2009-11-10 23:00:02 +0000 UTC m=+2.000000001
Read 10
Read 20
Read 30
Read 40
我想了解为什么最后一次读取的50没有在第二种情况下打印。

问题是您的wg.Done在错误的位置。它必须在您的goroutine中,但您在goroutine启动之前就执行了它,因此您的程序可能会在执行任何工作之前退出

更改此项:

defer wg.Done()
go func() {
为此:

go func() {
    defer wg.Done()
当然,您将有一个无限运行的goroutine,因为for循环没有退出条件。您需要添加一个,可能是通过检查频道关闭:

        select {
        case x, ok := <-c:
            if !ok { // channel was closed
                return
            }
            fmt.Println("Read", x)
        case t :=<-ti:
            fmt.Println("TIMED OUT with "+t.String())
        }
然后告诉你的主要围棋程序在完成后关闭频道:

c <- 40
c <- 50
close(c)  // We're done, so tell the goroutine to finish up
wg.Wait() // But wait until it's done

伟大的很好。还有一个问题。使用你的代码,我改变了如果!ok{return}如果ok{fmt.printlread,x}。而且它仍然运行良好。是什么打破了这个循环?当频道关闭时,select中是否有任何BTS处理?在这种情况下,中断循环的是程序退出。
c <- 40
c <- 50
close(c)  // We're done, so tell the goroutine to finish up
wg.Wait() // But wait until it's done