了解围棋中的竞争状况

时间:2017-03-03 03:32:58

标签: go time

我有以下非常简单的代码:

for i := 0; i < 100; i++ {
    tt := time.AfterFunc(10*time.Microsecond, func() { log.Fatal("bleh!") })
    time.Sleep(2 * time.Microsecond)
    tt.Stop()
}

现在看起来应该什么都不做了,当我在Go操场上运行它时,它会像预期的那样悄然退出,但是当我在Macbook上运行它时,我总是会遇到错误,例如:

go run example.go
2017/03/02 22:21:50 bleh!
2017/03/02 22:21:50 bleh!
exit status 1

我可以把时间放在AfterFunc确实相当高,即使高达50或100μs,我仍会偶尔得到“bleh!”和死亡。 Go中time.Sleep周围有哪些保证?什么是测试某些东西在特定时间内运行的更好方法?

2 个答案:

答案 0 :(得分:4)

保证time.Sleep(2 * time.Microsecond)至少 2微秒休眠,而time.AfterFunc(10 * time.Microsecond, ...)将在至少 10微秒后调用其回调。没有保证上限(底层操作系统可以做任何它想做的事情),并且没有保证相对排序 - 如果睡眠发生的时间超过10微秒,那么AfterFunc可能会在它之前或之后结束。

如果您使用了相当长的时间,那么很可能您会以正确的顺序观察发生的事情,因为Sleep goroutine会在之前安排好计时器到期了。但是,微秒是一个非常短的时间段,因此,从科学角度来说,彼此在几微秒内发生的最后期限很可能以他们想要的顺序发生。

游乐场使用modified runtime that fakes time,这也是测试的最佳方法。修改运行时对大多数人来说并不实用,但您可以尝试clockwork包,该包为真假时钟对象提供接口。否则,请自己采用相同的方法 - 如果您希望某些内容可以测试,则它可能不依赖time,因为time是全局且不可复制的。相反,它必须从生产中使用time的某个组件获取通知,但可以替换进行测试。

答案 1 :(得分:0)

func Sleep

  

睡眠暂停当前goroutine至少持续时间d。负或零持续时间会导致睡眠立即返回。

最重要的是“至少”。这意味着Sleep可能比传递的值花费更多的时间。此行为取决于操作系统的当前状态。

for i := 0; i < 100; i++ {
    tt := time.AfterFunc(
        10*time.Microsecond,
        func() {log.Fatal("bleh!") }) // has time to be executed
    time.Sleep(2 * time.Microsecond) // Slept more than 10 microsecond
    tt.Stop()
}
相关问题