Golang超时未使用通道执行

huangapple go评论65阅读模式
英文:

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 &lt;- 10
		}
	}()

	go func() {
		for {
			select {
			case i := &lt;-c1:
				fmt.Println(i)
			case &lt;-time.After(2000 * time.Millisecond):
				fmt.Println(&quot;TIMEOUT&quot;) // &lt;-- 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 := &lt;-c1:
		fmt.Println(i)
	case &lt;-timeout:
		fmt.Println(&quot;TIMEOUT&quot;) // Will get executed after 2 sec
	}
}

Output:

10
TIMEOUT
10
10
10
...

huangapple
  • 本文由 发表于 2016年1月20日 16:26:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/34894927.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定