Search code examples
gowaitsleep

What is the most time efficient way to guarantee at least one nanosecond has elapsed in Go? time.Sleep(time.Nanosecond) can take milliseconds


I have two function calls that I would like to separate by at least a nanosecond. But I want the delay to be as small as possible.

The code below shows an empty for loop is much more efficient at this than using time.Sleep(time.Nanosecond)

Is there an even more efficient way to guarantee at least one nanosecond has elapsed?

func TimeWaster () {
    start := uint64(time.Now().UnixNano())
    stop := uint64(time.Now().UnixNano())
    fmt.Println(time.Duration(stop-start))//0s
    //no nanoseconds pass

    start = uint64(time.Now().UnixNano())
    time.Sleep(time.Nanosecond)
    stop = uint64(time.Now().UnixNano())
    fmt.Println(time.Duration(stop-start))//6.9482ms
    //much *much* more than one nanosecond passes

    start = uint64(time.Now().UnixNano())
    for uint64(time.Now().UnixNano()) == start {
        //intentionally empty loop
    }
    stop = uint64(time.Now().UnixNano())
    fmt.Println(time.Duration(stop-start))//59.3µs
    //much quicker than time.Sleep(time.Nanosecond), but still much slower than 1 nanosecond
}

Solution

  • The package you're using strangely enforces uniqueness of values by time, so all you need to do is loop until the time package is no longer reporting the same value for the current nanosecond. This doesn't happen after 1 nanosecond, in fact the resolution of the UnixNano is about 100 nanoseconds on my machine and only updates about every 0.5 milliseconds.

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        fmt.Println(time.Now().UnixNano())
        smallWait()
        fmt.Println(time.Now().UnixNano())
    }
    
    func smallWait() {
        for start := time.Now().UnixNano(); time.Now().UnixNano() == start; {}
    }
    

    The loop is pretty self-explanatory, just repeat until the UnixNano() is different