Go 使用Timer.Reset()的计时器示例未按所述工作

Go 使用Timer.Reset()的计时器示例未按所述工作,go,timer,channels,routines,Go,Timer,Channels,Routines,我一直在使用示例,试图让我的第一个“go例程”运行,但当我让它运行时,它将无法按照go文档中关于timer.Reset()函数的规定工作 在我的情况下,我相信我这样做是很好的,因为我不在乎缓冲区中有什么,如果有的话。这一切都是为了触发case您创建了一个计时器并立即停止它: var tmr = time.NewTimer(time.Second) tmr.Stop() 这没有任何意义,我想这只是你的“意外” 但更进一步,在你的循环中: case _, ok := <-watche

我一直在使用示例,试图让我的第一个“go例程”运行,但当我让它运行时,它将无法按照go文档中关于timer.Reset()函数的规定工作


在我的情况下,我相信我这样做是很好的,因为我不在乎缓冲区中有什么,如果有的话。这一切都是为了触发
case您创建了一个计时器并立即停止它:

var tmr = time.NewTimer(time.Second)
tmr.Stop()
这没有任何意义,我想这只是你的“意外”

但更进一步,在你的循环中:

    case _, ok := <-watcher.Events:

case\ux,ok:=您使用time.Timer时未命中

试试这样简单的东西

package main

import (
    "fmt"
    "log"
    "time"
)

func main() {
    timer := time.NewTimer(time.Second)
    watcher := make(chan bool)
    done := make(chan bool)
    evs := make(chan bool)
    go func() {
        trigger := false
        for {
            select {
            case <-timer.C:
                if trigger {
                    trigger = false
                    evs <- true
                }
                timer.Reset(time.Second)

            case _, ok := <-watcher:
                if !ok {
                    return
                }
                trigger = true

            case <-done:
                fmt.Println(`DONE TRIGGERED`)
                return
            }
        }
    }()
    go func() {
        for e := range evs {
            log.Println("e", e)
        }
    }()
    // simulate multiple events
    watcher <- true
    watcher <- true
    watcher <- true
    watcher <- true
    <-time.After(time.Second + time.Millisecond*100)
    watcher <- true
    watcher <- true
    watcher <- true
        <-time.After(time.Second + time.Millisecond*100)

    fmt.Println("Hello, playground")
}
主程序包
进口(
“fmt”
“日志”
“时间”
)
func main(){
计时器:=time.NewTimer(time.Second)
观察者:=制造(chan bool)
完成:=制作(陈波)
电动汽车:=制造(chan bool)
go func(){
触发器:=假
为了{
挑选{
案例除了什么(q.v.),请注意

例如,假设该计划尚未收到t.C.的通知:

if !t.Stop() {
        <-t.C
}
是一个更好的例子。它执行一次非阻塞尝试,如果存在,将消耗计时器滴答声,如果没有计时器滴答声,则不会执行任何操作。无论调用
t.Stop
时计时器是否实际运行,这都会起作用。实际上,如果
t.Stop
返回
true
,即使在这种情况下,
t.Stop
停止了计时器,因此计时器从未设法将计时器滴答声放入通道中。(因此,如果通道中有数据,则必须是以前清除通道失败留下的数据。如果没有此类错误,则无需尝试接收。)

但是,如果其他人或其他goroutine正在或可能正在阅读该频道,您根本不应该这样做。尽管调用了
Stop
,但无法知道谁(您或他们)将在该频道中收到任何计时器滴答声


同时,如果你不打算进一步使用计时器,在通道中留下一个计时器滴答声(如果有)是相对无害的。当通道本身被垃圾收集时,它将被垃圾收集。当然,这是否合理取决于你用计时器做了什么,但在这些情况下,只需c就足够了所有
t.Stop
并忽略其返回值。

立即停止计时器并不是偶然的。我更希望创建它,但还没有开始计时,这样它只在另一个通道的事件发生时开始计时,但我不知道如何做。如果我只是将var设置为type*timer而不是启动计时器t当选择被卡住时,我必须启动计时器,然后立即停止。@Debashish:因为频道是同步点,
t.C
有一个缓冲区条目,所以可能性有限:要么频道中有一个滴答声,要么没有;要么有人走常规;我喜欢把他们看作人,或者gophers-*在接收中被*阻止,如果不是;当您调用
t.Stop
时,发送滴答声的goroutine(系统goroutine)已开始发送,或者尚未开始发送。因此:假设goroutine a在接收中被阻止(
虽然B可以尝试对此进行补偿,但最好是以不会卡住的方式编写A:即,它有一个条件接收,并带有一个
select
。让我们为Goroutine指定名称,以便于谈论它们。Goroutine A在
中,但这种代码通常很棘手。如果A有呢已经等待了5秒,而不是2秒,当B调用
t.Reset(10)
?S将在10秒后发送另一个滴答声时,S已经开始并正在发送滴答声。如果不知道a和B的其余代码,我们无法判断会发生什么。
package main

import (
    "fmt"
    "log"
    "time"
)

func main() {
    timer := time.NewTimer(time.Second)
    watcher := make(chan bool)
    done := make(chan bool)
    evs := make(chan bool)
    go func() {
        trigger := false
        for {
            select {
            case <-timer.C:
                if trigger {
                    trigger = false
                    evs <- true
                }
                timer.Reset(time.Second)

            case _, ok := <-watcher:
                if !ok {
                    return
                }
                trigger = true

            case <-done:
                fmt.Println(`DONE TRIGGERED`)
                return
            }
        }
    }()
    go func() {
        for e := range evs {
            log.Println("e", e)
        }
    }()
    // simulate multiple events
    watcher <- true
    watcher <- true
    watcher <- true
    watcher <- true
    <-time.After(time.Second + time.Millisecond*100)
    watcher <- true
    watcher <- true
    watcher <- true
        <-time.After(time.Second + time.Millisecond*100)

    fmt.Println("Hello, playground")
}
if !t.Stop() {
        <-t.C
}
if !t.Stop() {
        select {
        case <-t.C:
        default:
        }
}