英文:
Golang timeout is not executed with channels
问题
我正在使用goroutines/channels。以下是你的代码:
func main() {
    c1 := make(chan int, 1)
    go func() {
        for {
            time.Sleep(1500 * time.Millisecond)
            c1 <- 10
        }
    }()
    go func() {
        for {
            select {
            case i := <-c1:
                fmt.Println(i)
            case <-time.After(2000 * time.Millisecond):
                fmt.Println("TIMEOUT") // <-- Not Executed
            }
        }
    }()
    fmt.Scanln()
}
为什么超时的情况没有被执行?
英文:
I am using goroutines/channels.
Here is my code.
Why is the timeout case not getting executed?
func main() {
	c1 := make(chan int, 1)
	go func() {
		for {
			time.Sleep(1500 * time.Millisecond)
			c1 <- 10
		}
	}()
	go func() {
		for {
			select {
			case i := <-c1:
				fmt.Println(i)
			case <-time.After(2000 * time.Millisecond):
				fmt.Println("TIMEOUT") // <-- Not Executed
			}
		}
	}()
	fmt.Scanln()
}
答案1
得分: 4
你的超时不会发生,因为你的一个goroutine会在每1.5秒(左右)重复地向c1通道发送一个值,只有当c1中没有要接收的值时,超时才会发生。
一旦从c1接收到一个值,在下一次执行select时,将会进行一个新的time.After()调用,它会返回一个新的通道,该通道只会在另外2秒后发送一个值。上一个select执行的超时通道将被丢弃,不再使用。
要在2秒后接收超时,只需创建一次超时通道,例如:
timeout := time.After(2000 * time.Millisecond)
for {
	select {
	case i := <-c1:
		fmt.Println(i)
	case <-timeout:
		fmt.Println("TIMEOUT") // 2秒后执行
	}
}
输出:
10
TIMEOUT
10
10
10
...
英文:
Your timeout doesn't happen, because one of your goroutine sends a value on your c1 channel in every 1.5 seconds (or so) repeatedly, and your timeout would only happen if there is no value to be received from c1 for 2 seconds.
Once a value is received from c1, in the next iteration executing select again a new time.After() call will be made which which returns a new channel on which a value will only be sent after another 2 seconds. The timeout channel from the previous select execution is discarded and is not used anymore.
To receive the timeout after 2 seconds, create the timeout channel only once, e.g.:
timeout := time.After(2000 * time.Millisecond)
for {
	select {
	case i := <-c1:
		fmt.Println(i)
	case <-timeout:
		fmt.Println("TIMEOUT") // Will get executed after 2 sec
	}
}
Output:
10
TIMEOUT
10
10
10
...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论