比较 Goroutines 中的时间
Comparing times in Goroutines
我有一个用 Go 编写的测试:
func TestThings(t *testing.T) {
tCh := make(chan int64, 10000)
ctx, cx := context.WithTimeout(context.Background(), 20*time.Second)
defer cx()
wg := sync.WaitGroup{}
wg.Add(2)
go func(c context.Context) {
defer wg.Done()
defer close(tCh)
for {
select {
case <-c.Done():
return
default:
nt := time.Now()
tCh <- nt.UnixNano()
}
}
}(ctx)
go func(c context.Context) {
defer wg.Done()
for {
select {
case <-c.Done():
return
default:
v := <-tCh
nt := time.Now()
res := nt.UnixNano() - v
if res < 0 {
t.Errorf("got less than 0; diff: %d now: %d then: %d", res, nt.UnixNano(), v)
}
}
}
}(ctx)
wg.Wait()
}
运行 这个测试(有时)以结果结束:
go test -v -run TestThings ./test
=== RUN TestThings
test.go:48: got less than 0; diff: -33686100 now: 1639183246323013700 then: 1639183246356699800
test.go:48: got less than 0; diff: -33535000 now: 1639183246323171300 then: 1639183246356706300
test.go:48: got less than 0; diff: -33490200 now: 1639183246323222600 then: 1639183246356712800
test.go:48: got less than 0; diff: -33488300 now: 1639183246323231000 then: 1639183246356719300
test.go:48: got less than 0; diff: -33502600 now: 1639183246323241000 then: 1639183246356743600
test.go:48: got less than 0; diff: -33551600 now: 1639183246323249100 then: 1639183246356800700
...
--- FAIL: TestThings (20.01s)
FAIL
FAIL test 20.022s
FAIL
为什么接收Goroutine的时间有时早于发送Goroutine的时间?
我知道当涉及到计算机时,时钟通常是硬的和不可靠的,但我希望因为这些 Goroutines(也许?)在同一个进程中,但肯定在同一个主机上,调用 time.Now()
会 return 不断增加价值。或者至少不是“早期”的。
更新:
其他可能值得一提的事情:我 运行 在 Macbook Pro 上的 VSCode devcontainer 中。
正如@Peter 对引用 time package docs 的原始问题所评论的那样,time.Time
的序列化在设计上丢失了任何单调信息:
Because the monotonic clock reading has no meaning outside the current
process, the serialized forms generated by t.GobEncode
, t.MarshalBinary
,
t.MarshalJSON
, and t.MarshalText
omit the monotonic clock reading, and
t.Format
provides no format for it. Similarly, the constructors time.Date
,
time.Parse
, time.ParseInLocation
, and time.Unix
, as well as the unmarshalers
t.GobDecode
, t.UnmarshalBinary
. t.UnmarshalJSON
, and t.UnmarshalText
always
create times with no monotonic clock reading.
将原始问题中的代码片段更改为在 Goroutine 之间传递 time.Time
值没有问题。
我有一个用 Go 编写的测试:
func TestThings(t *testing.T) {
tCh := make(chan int64, 10000)
ctx, cx := context.WithTimeout(context.Background(), 20*time.Second)
defer cx()
wg := sync.WaitGroup{}
wg.Add(2)
go func(c context.Context) {
defer wg.Done()
defer close(tCh)
for {
select {
case <-c.Done():
return
default:
nt := time.Now()
tCh <- nt.UnixNano()
}
}
}(ctx)
go func(c context.Context) {
defer wg.Done()
for {
select {
case <-c.Done():
return
default:
v := <-tCh
nt := time.Now()
res := nt.UnixNano() - v
if res < 0 {
t.Errorf("got less than 0; diff: %d now: %d then: %d", res, nt.UnixNano(), v)
}
}
}
}(ctx)
wg.Wait()
}
运行 这个测试(有时)以结果结束:
go test -v -run TestThings ./test
=== RUN TestThings
test.go:48: got less than 0; diff: -33686100 now: 1639183246323013700 then: 1639183246356699800
test.go:48: got less than 0; diff: -33535000 now: 1639183246323171300 then: 1639183246356706300
test.go:48: got less than 0; diff: -33490200 now: 1639183246323222600 then: 1639183246356712800
test.go:48: got less than 0; diff: -33488300 now: 1639183246323231000 then: 1639183246356719300
test.go:48: got less than 0; diff: -33502600 now: 1639183246323241000 then: 1639183246356743600
test.go:48: got less than 0; diff: -33551600 now: 1639183246323249100 then: 1639183246356800700
...
--- FAIL: TestThings (20.01s)
FAIL
FAIL test 20.022s
FAIL
为什么接收Goroutine的时间有时早于发送Goroutine的时间?
我知道当涉及到计算机时,时钟通常是硬的和不可靠的,但我希望因为这些 Goroutines(也许?)在同一个进程中,但肯定在同一个主机上,调用 time.Now()
会 return 不断增加价值。或者至少不是“早期”的。
更新:
其他可能值得一提的事情:我 运行 在 Macbook Pro 上的 VSCode devcontainer 中。
正如@Peter 对引用 time package docs 的原始问题所评论的那样,time.Time
的序列化在设计上丢失了任何单调信息:
Because the monotonic clock reading has no meaning outside the current process, the serialized forms generated by
t.GobEncode
,t.MarshalBinary
,t.MarshalJSON
, andt.MarshalText
omit the monotonic clock reading, andt.Format
provides no format for it. Similarly, the constructorstime.Date
,time.Parse
,time.ParseInLocation
, andtime.Unix
, as well as the unmarshalerst.GobDecode
,t.UnmarshalBinary
.t.UnmarshalJSON
, andt.UnmarshalText
always create times with no monotonic clock reading.
将原始问题中的代码片段更改为在 Goroutine 之间传递 time.Time
值没有问题。