英文:
Why does Go‘s time.Now().UnixNano() return a smaller result?
问题
我使用time.Now().UnixNano()
来计算RPC的时间,但我发现第二次调用time.Now().UnixNano()
返回的时间戳比第一次调用的时间戳要小。
这段代码属于RPC客户端。我并发执行它数万次,有时会出现这种情况。
start := time.Now().UnixNano()
v := ck.Get(key)
end := time.Now().UnixNano()
if start > end {
fmt.Printf("TimeReverseErr found: callTime %v > returnTime %v\n", start, end)
}
以下是输出结果:
... found: callTime 1667161706348148000 > returnTime 1667161706304057000
... found: callTime 1667161706365079000 > returnTime 1667161706319597000
操作系统:macOS Monterey 12.6
Go版本:go1.18 darwin/amd64
完整的代码如下:
// 在RPC客户端中
func Get(cfg *config, ck *Clerk, key string, log *OpLog, cli int) string {
start := time.Now().UnixNano()
v := ck.Get(key)
end := time.Now().UnixNano()
if start > end {
fmt.Printf("TimeReverseErr found: callTime %v > returnTime %v", start, end)
}
cfg.op()
if log != nil {
log.Append(porcupine.Operation{
Input: models.KvInput{Op: 0, Key: key},
Output: models.KvOutput{Value: v},
Call: start,
Return: end,
ClientId: cli,
})
}
return v
}
我已经尝试了很多次,但问题仍然存在。
英文:
I use time.Now().UnixNano() to calculate the time of rpc, but I find that the second call to time.Now().UnixNano() returns a smaller timestamp than the first call.
This code belongs to the rpc client. I execute it concurrently tens of thousands of times and it sometimes comes up once.
start := time.Now().UnixNano()
v := ck.Get(key)
end := time.Now().UnixNano()
if start > end {
fmt.Printf("TimeReverseErr found: callTime %v > returnTime %v\n", start, end)
}
Here are outputs:
... found: callTime 1667161706348148000 > returnTime 1667161706304057000
... found: callTime 1667161706365079000 > returnTime 1667161706319597000
OS: macOS Monterey 12.6<br>
Go: go1.18 darwin/amd64
The complete code:
// in RPC Client
func Get(cfg *config, ck *Clerk, key string, log *OpLog, cli int) string {
start := time.Now().UnixNano()
v := ck.Get(key)
end := time.Now().UnixNano()
if start > end {
fmt.Printf("TimeReverseErr found: callTime %v > returnTime %v", start, end)
}
cfg.op()
if log != nil {
log.Append(porcupine.Operation{
Input: models.KvInput{Op: 0, Key: key},
Output: models.KvOutput{Value: v},
Call: start,
Return: end,
ClientId: cli,
})
}
return v
}
I have tried many times and this problem persists.
答案1
得分: 8
time.Now().UnixNano()
是一个墙钟读数,而不是单调钟读数。
> time: 单调时钟
>
> 操作系统提供了“墙钟”和“单调钟”两种时钟。墙钟受到时钟同步的影响,而单调钟则不受影响。一般规则是,墙钟用于显示时间,而单调钟用于测量时间。在这个包中,time.Now 返回的 Time 结构包含了墙钟读数和单调钟读数;后续的时间显示操作使用墙钟读数,而后续的时间测量操作,比如比较和减法,使用单调钟读数。
>
> 例如,下面的代码总是计算出大约 20 毫秒的正值时间间隔,即使在计时操作期间墙钟发生了变化:
>
> start := time.Now()
> ... 需要 20 毫秒的操作 ...
> t := time.Now()
> elapsed := t.Sub(start)
将你的代码改为使用 time.Now()
作为单调钟。例如:
package main
import (
"fmt"
"time"
)
func Get(key string) string { return "value" }
func main() {
key := "key"
start := time.Now()
v := Get(key)
end := time.Now()
since := end.Sub(start)
fmt.Println(start)
fmt.Println(end)
fmt.Println(since)
if since < 0 {
fmt.Println("start > end")
}
_ = v
}
m=+0.000018015
是一个单调钟值。
2022-10-31 00:38:30.415473095 -0400 EDT m=+0.000018015
2022-10-31 00:38:30.415473159 -0400 EDT m=+0.000018073
58ns
英文:
time.Now().UnixNano()
is a wall clock reading, it is not a monotonic clock reading.
> time: Monotonic Clocks
>
> Operating systems provide both a “wall clock,” which is subject to changes for clock synchronization, and a “monotonic clock,” which is not. The general rule is that the wall clock is for telling time and the monotonic clock is for measuring time. Rather than split the API, in this package the Time returned by time.Now contains both a wall clock reading and a monotonic clock reading; later time-telling operations use the wall clock reading, but later time-measuring operations, specifically comparisons and subtractions, use the monotonic clock reading.
>
> For example, this code always computes a positive elapsed time of approximately 20 milliseconds, even if the wall clock is changed during the operation being timed:
>
> start := time.Now()
> ... operation that takes 20 milliseconds ...
> t := time.Now()
> elapsed := t.Sub(start)
Rephrase your code to use time.Now()
as a monotonic clock. For example,
package main
import (
"fmt"
"time"
)
func Get(key string) string { return "value" }
func main() {
key := "key"
start := time.Now()
v := Get(key)
end := time.Now()
since := end.Sub(start)
fmt.Println(start)
fmt.Println(end)
fmt.Println(since)
if since < 0 {
fmt.Println("start > end")
}
_ = v
}
m=+0.000018015
is a monotonic clock value.
2022-10-31 00:38:30.415473095 -0400 EDT m=+0.000018015
2022-10-31 00:38:30.415473159 -0400 EDT m=+0.000018073
58ns
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论