混合使用`timer.Ticker`和`timer.Tick`/`timer.After`会忽略`Tick`/`After`中的计时器。

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

Mixing timer.Ticker with timer.Tick / timer.After; ignores timer from Tick/After

问题

我正在玩通道,并遇到了一个问题。我有一个循环,我想在一段固定的时间后停止,比如5秒,我还想通过300毫秒来去抖动迭代。

第一个代码片段似乎可以去抖动,但从未触发达到5秒的情况。对于time.Tick(time.Second * 5),我也有类似的结果。

第二个代码片段对我有效;使用另一个计时器。我不明白为什么这个代码有效而前一个代码无效,尤其是因为文档中描述的time.Tick()等效于只暴露通道C的time.NewTicker()。

我在这里漏掉了什么?这两个代码片段有显著的区别吗?

英文:

I'm playing around with channels and I'm running into something here.
I have a loop, I want to stop after a set period of time, say 5 seconds,
I also want to debounce iterations by say 300 milliseconds.

func pump() <-chan interface{} {
	c := make(chan interface{})

	// use for loop
	// stop after 5 seconds

	d := time.NewTicker(time.Millisecond * 2000)

	go func() {

	myLoop:
		for {
			select {
			case <-time.After(time.Second * 5):
				fmt.Println("Its five seconds")
				close(c)
				d.Stop()
				break myLoop
			default:
				c <- rand.Int()
				<-d.C
				fmt.Println("After wait / debounce")
			}
		}
	}()

	return c
}

While the above seems to debounce, it never triggers the case for hitting 5 seconds.
I have similar results for time.Tick(time.Second * 5)

func pump() <-chan interface{} {
	c := make(chan interface{})

	// use for loop
	// stop after 5 seconds

	d := time.NewTicker(time.Millisecond * 2000)
	t := time.NewTicker(time.Second * 5)

	go func() {

	myLoop:
		for {
			select {
			case <-t.C:
				fmt.Println("Its five seconds")
				close(c)
				t.Stop()
				d.Stop()
				break myLoop
				// case <-d.C:
				// 	fmt.Println("its a sleep")
			default:
				c <- rand.Int()
				// 	// slow down
				<-d.C
				// 	fmt.Println("After 3000 milliseconds")
			}
		}
	}()

	return c
}
func pump() <-chan interface{} {
	c := make(chan interface{})

	// use for loop
	// stop after 5 seconds

	d := time.NewTicker(time.Millisecond * 2000)
	t := time.NewTicker(time.Second * 5)

	go func() {

	myLoop:
		for {
			select {
			case <-t.C:
				// case <-time.After(time.Second * 5):
				fmt.Println("Its five seconds")
				close(c)
				t.Stop()
				d.Stop()
				break myLoop
			case <-d.C:
				c <- rand.Int()
			}
		}
	}()

	return c
}

The above works for me; using another ticker. I dont udnerstand why this works where the former fails, especially as a time.Tick() is described in the documentation as being equivalent to a time.NewTicker() with only the channel C exposed.

What am I missing here? are the code snippets significantly different?

答案1

得分: 1

根据我的评论:

for {
   select {
      case <-time.After(time.Second * 5):
         ...
      default:
         ...
   }
}

每次迭代都会创建一个新的计时器(time.After)。这意味着计时器永远不会触发(因为始终会选择default分支)。你可以通过在循环外部创建计时器来避免这种情况(playground):

timer := time.After(time.Second * 5)

myLoop:
for {
   select {
      case <-timer:
         break myLoop
      default:
         ...
   }
}

你的第二个示例在我这里运行正常(参见之前引用的playground)。请注意,我不确定这些示例是否能实现你所期望的结果,因为你并没有明确定义。

英文:

As per my comment:

for {
   select {
      case &lt;-time.After(time.Second * 5):
         ...
      default:
         ...
   }
}

Will create a new timer (time.After) each iteration. This means that the timer will never fire (because the default) case will always be selected. You can prevent this by creating the timer outside of the loop (playground):

timer := time.After(time.Second * 5)

myLoop:
for {
   select {
      case &lt;-timer:
         break myLoop
      default:
         ...
   }
}

Your second example worked OK for me (see the previously referenced playground). Note that I'm unsure if any of these will accomplish the result you are looking for because that was not really defined.

huangapple
  • 本文由 发表于 2022年9月3日 10:44:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/73589299.html
匿名

发表评论

匿名网友

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

确定