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

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
}

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

Related

Go: Unexpected Results from time.Sleep

Running this code (as a built executable, not with the debugger):
package main
import (
"fmt"
"time"
)
func main() {
startTime := time.Now()
for i := 0; i < 1000; i++ {
time.Sleep(1 * time.Millisecond)
}
fmt.Printf("%d\n", time.Since(startTime).Milliseconds())
}
I get the output:
15467
This seems like a major overhead for calling the time.Sleep() function; it's essentially taking 15ms per loop iteration, even though it's only sleeping for 1ms in each loop. This suggests that there's a 14ms overhead for running an iteration of the loop and initiating a sleep.
If we adjust the sleep duration:
package main
import (
"fmt"
"time"
)
func main() {
startTime := time.Now()
for i := 0; i < 1000; i++ {
time.Sleep(10 * time.Millisecond)
}
fmt.Printf("%d\n", time.Since(startTime).Milliseconds())
}
I get the output:
15611
This is essentially the same duration, even though it should be sleeping for 10x as long. This kills the idea that there's a 14ms overhead for the loop iteration and initiating the sleep, because if that were the case, it would be (14+10)*1000 = 24000ms total, which it is not.
What am I missing? Why would this code take the same duration to execute, whether the sleep duration is 1ms or 10ms?
Note that I've tried running this in the Go playground but get different results; I think it handles sleeping differently. These results are consistent on my laptop, which is running an i7-10510.
It is probably related to the frequency of the system's timer. For example, on Windows the clock ticks every 15 milliseconds (source):
For example, for Windows running on an x86 processor, the default interval between system clock ticks is typically about 15 milliseconds, and the minimum interval between system clock ticks is about 1 millisecond. Thus, the expiration time of a default-resolution timer (which ExAllocateTimer creates if the EX_TIMER_HIGH_RESOLUTION flag is not set) can be controlled only to within about 15 milliseconds, but the expiration time of a high-resolution timer can be controlled to within a millisecond.
If you need a higher precision timer you probably need to find a way to use High-Resolution Timers.
More information can be found in the threads below:
https://github.com/golang/go/issues/44343
https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/
https://github.com/golang/go/issues/44343

Creating a time.Duration from float64 seconds

I have a float64 containing a duration in seconds. I'm looking for a way to convert this value to a time.Duration. I'm able to perform this conversion, but I'm wondering if there is not a more elegant way.
The approach I have is this:
var timeout float64 // input value of float type
var res time.Duration // result value of time.Duration type
res += time.Duration(math.Round(timeout)) * time.Second
timeout -= math.Round(timeout)
timeout *= 1000
res += time.Duration(math.Round(timeout)) * time.Millisecond
timeout -= math.Round(timeout)
timeout *= 1000
res += time.Duration(math.Round(timeout)) * time.Microsecond
timeout -= math.Round(timeout)
timeout *= 1000
res += time.Duration(math.Round(timeout)) * time.Nanosecond
return res
What I dislike about this is that it is cumbersome and not reliable. I'd expect Go to supply something like this out of the box and to perform these conversions in a way that detects overflows and similar range violations. It seems that Go is not there yet, but maybe I missed something obvious, hence my question.
Notes:
This question doesn't address my needs, because it is rather related to the opposite way of conversion. That conversion is actually pretty painless, which makes the it even more surprising that the one I need isn't there.
Why don't I use milliseconds instead? Simple reason: Consistency, KISS principle, principle of least surprise. The SI unit for time is the second. Everything else is only derived from this, so I use this as a default.
Nitpick concerning the previous statement: Go itself says "There is no definition for units of Day or larger to avoid confusion across daylight savings time zone transitions.". They missed the point, because they still have minutes and hours, even though there are minutes with 58..61 seconds. Not a big deal, just mentioning it for completeness.
As JimB's comment shows, multiply the number of seconds by the number of duration units per second. Durations are measured in nanoseconds, but your code does not need to know that detail.
return time.Duration(timeout * float64(time.Second))
Convert to floating point for the multiplication and convert to duration to get the result.
I'm not sure what the issue is here. Your request is very simple to implement:
package main
import (
"fmt"
"time"
)
func duration(f float64) time.Duration {
return time.Duration(f * 1e9)
}
func main() {
t := duration(9)
fmt.Println(t) // 9s
}
It's literally one line of code, what is not elegant about that? The only way it could be more elegant, is if time.Duration was float64 natively. And that just doesn't make sense, as Go doesn't track anything smaller than a nanosecond.
https://golang.org/pkg/time#Duration

How to benchmark init() function

I was playing with following Go code which calculates Population count using lookup table:
package population
import (
"fmt"
)
var pc [256]byte
func init(){
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
}
func countPopulation() {
var x uint64 = 65535
populationCount := int(pc[byte(x>>(0*8))] +
pc[byte(x>>(1*8))] +
pc[byte(x>>(2*8))] +
pc[byte(x>>(3*8))] +
pc[byte(x>>(4*8))] +
pc[byte(x>>(5*8))] +
pc[byte(x>>(6*8))] +
pc[byte(x>>(7*8))])
fmt.Printf("Population count: %d\n", populationCount)
}
I have written following benchmark code to check performance of above code block:
package population
import "testing"
func BenchmarkCountPopulation(b *testing.B) {
for i := 0; i < b.N; i++ {
countPopulation()
}
}
Which gave me following result:
100000 18760 ns/op
PASS
ok gopl.io/ch2 2.055s
Then I moved the code from init() function to the countPopulation() function as below:
func countPopulation() {
var pc [256]byte
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
var x uint64 = 65535
populationCount := int(pc[byte(x>>(0*8))] +
pc[byte(x>>(1*8))] +
pc[byte(x>>(2*8))] +
pc[byte(x>>(3*8))] +
pc[byte(x>>(4*8))] +
pc[byte(x>>(5*8))] +
pc[byte(x>>(6*8))] +
pc[byte(x>>(7*8))])
fmt.Printf("Population count: %d\n", populationCount)
}
and once again ran the same benchmark code, which gave me following result:
100000 20565 ns/op
PASS
ok gopl.io/ch2 2.303s
After observing both the results it is clear that init() function is not in the scope of benchmark function. That's why first benchmark execution took lesser time compared to second execution.
Now I have another question which I am looking to get answer for.
If I need to benchmark only the init() method, considering there can be multiple init() functions in a package. How is it done in golang?
Thanks in advance.
Yes there can be multiple init()'s in a package, in-fact you can have multiple init()'s in a file. More information about init can be found here. Remember that init() is automatically called one time before your program's main() is even started.
The benchmark framework runs your code multiple times (in your case 100000). This allows it to measure very short functions, as well as very long functions. It doesn't make sense for benchmark to include the time for init(). The problem you are having is that you are not understanding the purpose of benchmarking. Benchmarking lets you compare two or more separate implementations to determine which one is faster (also you can compare performance based on input of the same function). It does not tell you where you should be doing that.
What you are basically doing is known as Premature Optimization. It's where you start optimizing code trying to make it as fast as possible, without knowing where your program actually spends most of its time. Profiling is the process of measuring the time and space complexity of a program. In practice, it allows you to see where your program is spending most of its time. Using that information, you can write more efficient functions. More information about profiling in go can be found in this blog post.

Golang Timers with 0 length

I've written a code snipped that creates a timer with a 0 length time, and it does not immediately expire (which is what I expected). A very short sleep call does make it expire, but I'm confused as to why.
The reason I care is that the code using this idea has a snippet that returns 0 on a low probability error, with the idea that the timer should be set to immediately expire, and retry a function. I do not believe that the nanosecond sleep needed here will affect my implementation, but it bothers me.
Did I make a mistake, is this expected behaviour?
Thanks!
package main
import (
"fmt"
"time"
)
func main() {
testTimer := time.NewTimer(time.Duration(0) * time.Millisecond)
fmt.Println(Expired(testTimer))
time.Sleep(time.Nanosecond)
fmt.Println(Expired(testTimer))
}
func Expired(T *time.Timer) bool {
select {
case <-T.C:
return true
default:
return false
}
}
Playground link: https://play.golang.org/p/xLLHoR8aKq
Prints
false
true
time.NewTimer() does not guarantee maximum wait time. It only guarantees a minimum wait time. Quoting from its doc:
NewTimer creates a new Timer that will send the current time on its channel after at least duration d.
So passing a zero duration to time.NewTimer(), it's not a surprise the returned time.Timer is not "expired" immediately.
The returned timer could be "expired" immediately if the implementation would check if the passed duration is zero, and would send a value on the timer's channel before returning it, but it does not. Instead it starts an internal timer normally as it does for any given duration, which will take care of sending a value on its channel, but only some time in the future.
Note that with multiple CPU cores and with runtime.GOMAXPROCS() being greater than 1 there is a slight chance that another goroutine (internal to the time package) sends a value on the timer's channel before NewTimer() returns, but this is a very small chance... Also since this is implementation detail, a future version might add this "optimization" to check for 0 passed duration, and act as you expected it, but as with all implementation details, don't count on it. Count on what's documented, and expect no more.
Go's timer functions guarantee to sleep at least the specified time. See the docs for Sleep and NewTimer respectively:
Sleep pauses the current goroutine for at least the duration d. A negative or zero duration causes Sleep to return immediately.
NewTimer creates a new Timer that will send the current time on its channel after at least duration d.
(emphasis added)
In your situation, you should probably just not use a timer in the situation that you don't want to sleep at all.
This is due to the internal time it takes to set up the timer object. If you'll note in the playground link below the timer does expire at the proper time, but the internal go routine that sets it up and starts it takes longer than your Expire function does to check it.
When the Timer expires, the current time will be sent on C (the channel)
So you'll notice that after it expires, it still sends the original time, because it has expired even before the nanosecond Sleep finished.
https://play.golang.org/p/Ghwq9kJq3J
package main
import (
"fmt"
"time"
)
func main() {
testTimer := time.NewTimer(0 * time.Millisecond)
Expired(testTimer)
time.Sleep(time.Nanosecond)
Expired(testTimer)
n := time.Now()
fmt.Printf("after waiting: %d\n", n.UnixNano())
}
func Expired(T *time.Timer) bool {
select {
case t:= <-T.C:
fmt.Printf("expired %d\n", t.UnixNano())
return true
default:
n := time.Now()
fmt.Printf("not expired: %d\n", n.UnixNano())
return false
}
}

Distribute the same keyword to multiple goroutines

I have something like this mock (code below) which distributes the same keyword out to multiple goroutines, except the goroutines all take different amount of times doing things with the keyword but can operate independently of each other so they don't need any synchronization. The solution given below to distribute clearly synchronizes the goroutines.
I just want to toss this idea out there to see how other people would deal with this type of distribution, as I assume it is fairly common and someone else has thought about it before.
Here are some other solutions I have thought up and why they seem kinda meh to me:
One goroutine for each keyword
Each time a new keyword comes in spawn a goroutine to handle the distribution
Give the keyword a bitmask or something for each goroutine to update
This way once all of the workers have touched the keyword it can be deleted and we can move on
Give each worker its own stack to work off of
This seems kinda appealing, just give each worker a stack to add each keyword to, but we would eventually run into a problem of a ton of memory being taken up since it is planned to run so long
The problem with all of these is that my code is supposed to run for a long time, unwatched, and that would lead to either a huge build up of keywords or goroutines due to the lazy worker taking longer than the others. It almost seems like it'd be nice to give each worker its own Amazon SQS queue or implement something similar to that myself.
EDIT:
Store the keyword outside the program
I just thought of doing it this way instead, I could perhaps just store the keyword outside the program until they all grab it and then delete it once it has been used up. This sits ok with me actually, I don't have a problem with using up disk space
Anyway here is an example of the approach that waits for all to finish:
package main
import (
"flag"
"fmt"
"math/rand"
"os"
"os/signal"
"strconv"
"time"
)
var (
shutdown chan struct{}
count = flag.Int("count", 5, "number to run")
)
type sleepingWorker struct {
name string
sleep time.Duration
ch chan int
}
func NewQuicky(n string) sleepingWorker {
var rq sleepingWorker
rq.name = n
rq.ch = make(chan int)
rq.sleep = time.Duration(rand.Intn(5)) * time.Second
return rq
}
func (r sleepingWorker) Work() {
for {
fmt.Println(r.name, "is about to sleep, number:", <-r.ch)
time.Sleep(r.sleep)
}
}
func NewLazy() sleepingWorker {
var rq sleepingWorker
rq.name = "Lazy slow worker"
rq.ch = make(chan int)
rq.sleep = 20 * time.Second
return rq
}
func distribute(gen chan int, workers ...sleepingWorker) {
for kw := range gen {
for _, w := range workers {
fmt.Println("sending keyword to:", w.name)
select {
case <-shutdown:
return
case w.ch <- kw:
fmt.Println("keyword sent to:", w.name)
}
}
}
}
func main() {
flag.Parse()
shutdown = make(chan struct{})
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
close(shutdown)
}()
x := make([]sleepingWorker, *count)
for i := 0; i < (*count)-1; i++ {
x[i] = NewQuicky(strconv.Itoa(i))
go x[i].Work()
}
x[(*count)-1] = NewLazy()
go x[(*count)-1].Work()
gen := make(chan int)
go distribute(gen, x...)
go func() {
i := 0
for {
i++
select {
case <-shutdown:
return
case gen <- i:
}
}
}()
<-shutdown
os.Exit(0)
}
Let's assume I understand the problem correctly:
There's not too much you can do about it I'm afraid. You have limited resources (assuming all resources are limited) so if data to your input is written faster then you process it, there will be some synchronisation needed. At the end the whole process will run as quickly as the slowest worker anyway.
If you really need data from the workers available as soon as possible, the best you can do is to add some kind of buffering. But the buffer must be limited in size (even if you run in the cloud it would be limited by your wallet) so assuming never ending torrent of input it will only postpone the choke until some time in the future where you will start seeing "synchronisation" again.
All the ideas you presented in your questions are based on buffering the data. Even if you run a routine for every keyword-worker pair, this will buffer one element in every routine and, unless you implement the limit on total number of routines, you'll run out of memory. And even if you always leave some room for the quickest worker to spawn a new routine, the input queue won't be able to deliver new items as it would be choked on the slowest worker.
Buffering would solve your problem if on average you input is slower than processing time, but you have occasional spikes. If your buffer is big enough you can than accommodate the increase of throughput and maybe your quickest worker won't notice a thing.
Solution?
As go comes with buffered channels, this is the easiest to implement (also suggested by icza in the comment). Just give each worker a buffer. If you know which worker is the slowest, you can give it a bigger buffer. In this scenario you're limited by the memory of your machine.
If you're not happy with the single-machine memory limit then yes, per one of your ideas, you can "simply" store the buffer (queue) for each worker on the hard drive. But this is also limited and just postpones the blocking scenario until later. This is essentially the same as your Amazon SQS proposal (you could keep buffer in the cloud, but you need either limit it reasonably or prepare for the bill.)
The final note, depending on the system you're building, it might be not a good idea to buffer items in such a massive scale allowing to build up the backlog for the slower workers – it's often not desirable to have a worker hours, days, weeks behind the input flow and this is what would happen with an infinite buffer. The real answer then would be: improve your slowest worker to process things faster. (And add some buffering to improve the experience.)

Resources