为什么在 goroutine 中声明时 benbjohnson/clock 模拟计时器不执行?

此代码按我预期的方式工作


import (

    "fmt"

    "time"


    "github.com/benbjohnson/clock"

)


func main() {

    mockClock := clock.NewMock()

    timer := mockClock.Timer(time.Duration(2) * time.Second)

    go func() {

        <-timer.C

        fmt.Println("Done")

    }()

    mockClock.Add(time.Duration(10) * time.Second)

    time.Sleep(1)

}


它按我的预期打印“完成”。而这个功能不


import (

    "fmt"

    "time"


    "github.com/benbjohnson/clock"

)


func main() {

    mockClock := clock.NewMock()

    go func() {

        timer := mockClock.Timer(time.Duration(2) * time.Second)

        <-timer.C

        fmt.Println("Done")

    }()

    mockClock.Add(time.Duration(10) * time.Second)

    time.Sleep(1)

}

这里唯一的区别是我在 goroutine 外部和内部声明定时器。该mockClock Timer()方法有一个指针接收器并返回一个指针。我无法解释为什么第一个有效而第二个无效。


RISEBY
浏览 95回答 1
1回答

弑天下

该软件包benbjohnson/clock提供模拟时间设施。他们的文档特别指出:计时器和 Tickers 也由同一个模拟时钟控制。它们只会在时钟向前移动时执行所以当你调用时mockClock.Add,它会依次执行定时器/代码。该库还添加了连续的 1 毫秒睡眠,以人为地屈服于其他 goroutines。当计时器/自动收报机在 goroutine 外部声明时,即在调用之前mockClock.Add,到mockClock.Add被调用时,模拟时间确实有一些东西要执行。库的内部睡眠足以让子 goroutine 在程序退出之前在自动收报机上接收并打印“完成”。当 ticker 在 goroutine 中声明时,到 timemockClock.Add被调用时,模拟时间没有要执行的 ticker,Add基本上什么都不做。内部睡眠确实给了子 goroutine 运行的机会,但是接收到 ticker 现在只会阻塞;main 然后恢复并退出。您还可以查看存储库自述文件中的代码示例:mock := clock.NewMock()count := 0// Kick off a timer to increment every 1 mock second.go func() {&nbsp; &nbsp; ticker := mock.Ticker(1 * time.Second)&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; <-ticker.C&nbsp; &nbsp; &nbsp; &nbsp; count++&nbsp; &nbsp; }}()runtime.Gosched()// Move the clock forward 10 seconds.mock.Add(10 * time.Second)// This prints 10.fmt.Println(count)这用于在调用之前runtime.Gosched()屈服于子 goroutine&nbsp;。这个程序的顺序基本上是:mock.Addclock.NewMock()count := 0生成子 goroutineruntime.Gosched(), 让步给子 goroutineticker := mock.Ticker(1 * time.Second)阻塞<-ticker.C(模拟时钟还没有向前移动)恢复主要mock.Add, 它将时钟向前移动并再次让步给子 goroutinefor循环<-ticker.C打印 10出口按照相同的逻辑,如果您将 a 添加runtime.Gosched()到第二个代码段,它将按预期工作,就像存储库的示例一样。游乐场:https ://go.dev/play/p/ZitEdtx9GdL但是,不要依赖runtime.Gosched()生产代码,甚至可能不要依赖测试代码,除非您非常确定自己在做什么。最后,请记住time.Sleep(1)休眠一纳秒。
打开App,查看更多内容
随时随地看视频慕课网APP