|
|
 |
 |
 |
 |
Ruby Programming Language
|
 |
 |
 |
 |
 |
 |
 |
 |
Sleeping between 1e-2 and 1e-6s
I noticed that ruby uses a different way to sleep with values >1e-6s. I added my observations below. My question is now: what is the suggested way to sleep e.g. 0.001s? 10000.times { sleep(0.0000001) }? Cant' really be it, no? :) The results: $ ruby sleeper.rb 100x sleeping 0.01000000s: 0.01003044s per sleep, runtime: 1.00304s 100x sleeping 0.00100000s: 0.01006163s per sleep, runtime: 1.00616s 100x sleeping 0.00010000s: 0.01007538s per sleep, runtime: 1.00754s 100x sleeping 0.00001000s: 0.01011209s per sleep, runtime: 1.01121s 100x sleeping 0.00000100s: 0.01008325s per sleep, runtime: 1.00832s 100x sleeping 0.00000010s: 0.00001131s per sleep, runtime: 0.00113s 100x sleeping 0.00000001s: 0.00000986s per sleep, runtime: 0.00099s The sleeper.rb file: #!/usr/bin/ruby def bench(n=1, &b) start = Time.now n.to_i.times(&b) Time.now-start end [0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001].each { |s| r = bench(100) { sleep(s) } printf "100x sleeping %.8fs: %.8fs per sleep, runtime: %.5fs\n", s, r/100, r }
Regards Stefan -- Posted via http://www.ruby-forum.com/.
On Tue, Jun 05, 2007 at 12:57:30AM +0900, Stefan Rusterholz wrote: > I noticed that ruby uses a different way to sleep with values >1e-6s. > I added my observations below. My question is now: what is the suggested > way to sleep e.g. 0.001s? > 10000.times { sleep(0.0000001) }? Cant' really be it, no? :)
You've hit the granularity of the thread scheduler. On my machine, running your test code, it appears to be 4ms: $ ruby sleep.rb 100x sleeping 0.01000000s: 0.01210674s per sleep, runtime: 1.21067s 100x sleeping 0.00100000s: 0.00407440s per sleep, runtime: 0.40744s 100x sleeping 0.00010000s: 0.00411841s per sleep, runtime: 0.41184s 100x sleeping 0.00001000s: 0.00411971s per sleep, runtime: 0.41197s 100x sleeping 0.00000100s: 0.00000858s per sleep, runtime: 0.00086s 100x sleeping 0.00000010s: 0.00000852s per sleep, runtime: 0.00085s 100x sleeping 0.00000001s: 0.00000852s per sleep, runtime: 0.00085s Ruby is not a precision real-time environment - and neither are Unix or Windows for that matter. If you really need such a short pause, you could use ruby-inline and call nanosleep() or usleep() or select() C functions, depending on what's available on your platform. You'll block the entire Ruby interpreter for that period of time, i.e. Ruby won't be able to do work in another thread at the same time, but at least the CPU will be available to other processes on your machine, unlike a spinloop as you propose above. But you should think carefully about what you're doing. For example, if you were trying to do loop do send_packet precision_sleep(0.001) end then you will certainly send less than 1000 packets per second, and the actual rate you send at will be variable. It may be better to send packets at an *average* rate of 1000 packets per second, even if they go in bursts of 10 or 12 packets. Brian.
Brian Candler wrote: > Ruby is not a precision real-time environment - and neither are Unix or > Windows for that matter.
Certainly not. But even with Ruby microsecond sleep should be possible. > If you really need such a short pause, you could use ruby-inline and > call nanosleep() or usleep() or select() C functions
That would interrupt all threads. But it could still be an option for sleeps < 0.01s. I.e. sleep everything > 0.01s with thread_wait_for and switch to usleep for smaller values. Of course it would be nice to somehow get the granularity of the scheduler and switch at that. > loop do > send_packet > precision_sleep(0.001) > end > then you will certainly send less than 1000 packets per second
The situation is indeed similar to the above. I'm also well aware of that problem. It's not really an issue, though as I don't sleep the interval but the time left in the interval (measured from an absolute start, not the last time the event happened). After digging in the code I also understand what happens in that gap. timeval.tv_usec is a long representing microseconds. Those values are rounded down to 0, so I assume it effectively doesn't sleep. Regards Stefan -- Posted via http://www.ruby-forum.com/.
|
 |
 |
 |
 |
|