为什么这段 Golang 代码无法在多个 time.After 通道之间进行选择?

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

Why doesn't this Golang code to select among multiple time.After channels work?

问题

为什么这段 Golang 代码中选择多个 time.After 通道的部分不起作用?

请看下面的代码。"timeout" 消息从未被输出。为什么呢?

package main

import (
	"fmt"
	"time"
)

func main() {
	count := 0
	for {
		select {
		case <-time.After(1 * time.Second):
			count++
			fmt.Printf("tick %d\n", count)
			if count >= 5 {
				fmt.Printf("ugh\n")
				return
			}
		case <-time.After(3 * time.Second):
			fmt.Printf("timeout\n")
			return
		}
	}
}

在 Playground 上运行它:http://play.golang.org/p/1gku-CWVAh

输出:

tick 1
tick 2
tick 3
tick 4
tick 5
ugh
英文:

Why doesn't this Golang code to select among multiple time.After channels work?

See code below. The 'timeout' message is never issued. Why?

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {
	count := 0
	for {
		select {
		case &lt;-time.After(1 * time.Second):
			count++
			fmt.Printf(&quot;tick %d\n&quot;, count)
			if count &gt;= 5 {
				fmt.Printf(&quot;ugh\n&quot;)
				return
			}
		case &lt;-time.After(3 * time.Second):
			fmt.Printf(&quot;timeout\n&quot;)
			return
		}
	}
}

Run it on Playground: http://play.golang.org/p/1gku-CWVAh

Output:

tick 1
tick 2
tick 3
tick 4
tick 5
ugh

答案1

得分: 15

因为time.After是一个函数,所以在每次迭代中它都会返回一个新的通道。如果你希望这个通道在所有迭代中保持相同,你应该在循环之前保存它:

timeout := time.After(3 * time.Second)
for {
	select {
	//...
	case <-timeout:
		fmt.Printf("超时\n")
		return
	}
}

Playground: http://play.golang.org/p/muWLgTxpNf.

英文:

Because time.After is a function, so on every iteration it returns a new channel. If you want this channel to be the same for all iterations, you should save it before the loop:

timeout := time.After(3 * time.Second)
for {
	select {
	//...
	case &lt;-timeout:
		fmt.Printf(&quot;timeout\n&quot;)
		return
	}
}

Playground: http://play.golang.org/p/muWLgTxpNf.

答案2

得分: 5

即使<a href="https://stackoverflow.com/users/1892060/ainar-g">@Ainar-G</a>已经提供了答案,另一种可能性是使用time.Tick(1e9)来生成每秒钟的时间间隔,然后在指定的时间段后监听timeAfter通道。

package main

import (
    "fmt"
    "time"
)

func main() {
    count := 0
    timeTick := time.Tick(1 * time.Second)
    timeAfter := time.After(5 * time.Second)
    
    for {
        select {
        case <-timeTick:
            count++
            fmt.Printf("tick %d\n", count)
            if count >= 5 {
                fmt.Printf("ugh\n")
                return
            }
        case <-timeAfter:
            fmt.Printf("timeout\n")
            return
        }
    }
}
英文:

Even <a href="https://stackoverflow.com/users/1892060/ainar-g">@Ainar-G</a> has already provided the answer, another possibility is to use time.Tick(1e9) to generate a time tick on every second and then listen for timeAfterchannel after the specified period.

package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

func main() {
    count := 0
	timeTick := time.Tick(1 * time.Second)
	timeAfter := time.After(5 * time.Second)
	
    for {
        select {
        case &lt;-timeTick:
            count++
            fmt.Printf(&quot;tick %d\n&quot;, count)
            if count &gt;= 5 {
                fmt.Printf(&quot;ugh\n&quot;)
                return
            }
        case &lt;-timeAfter:
            fmt.Printf(&quot;timeout\n&quot;)
            return
        }
    }
}

huangapple
  • 本文由 发表于 2016年1月27日 19:52:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/35036653.html
匿名

发表评论

匿名网友

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

确定