我在Rubymine 8.0.3中运行Ruby 2.2
我的机器运行的是带有Intel内核i7-4710MQ的Windows 7 Pro
我已经能够在这台机器上用C ++,Java,Python和JS达到~411 ns的精度,但似乎无法找到在Ruby中获得这种性能的方法,因为内置的时间库是好的仅适用于ms。
我可以对我的测试进行编程以容忍这种降低的精度,但是是否可以结合使用Windows QPC API来改进执行时间的评估?
我确定时钟滴答精度的测试代码如下:
numTimes = 10000
times = Array.new(numTimes)
(0...(numTimes)).each do |i|
times[i] = Time.new
end
durations = []
(0...(numTimes - 1)).each do |i|
durations[i] = times[i+1] - times[i]
end
# Output duration only if the clock ticked over
durations.each do |duration|
if duration != 0
p duration.to_s + ','
end
end
以下代码将QPC合并为here
require "Win32API"
QueryPerformanceCounter = Win32API.new("kernel32",
"QueryPerformanceCounter", 'P', 'I')
QueryPerformanceFrequency = Win32API.new("kernel32",
"QueryPerformanceFrequency", 'P', 'I')
def get_ticks
tick = ' ' * 8
get_ticks = QueryPerformanceCounter.call(tick)
tick.unpack('q')[0]
end
def get_freq
freq = ' ' * 8
get_freq = QueryPerformanceFrequency.call(freq)
freq.unpack('q')[0]
end
def get_time_diff(a, b)
# This function takes two QPC ticks
(b - a).abs.to_f / (get_freq)
end
numTimes = 10000
times = Array.new(numTimes)
(0...(numTimes)).each do |i|
times[i] = get_ticks
end
durations = []
(0...(numTimes - 1)).each do |i|
durations[i] = get_time_diff(times[i+1], times[i])
end
durations.each do |duration|
p (duration * 1000000000).to_s + ','
end
此代码返回机器上约22-75微秒的刻度之间的持续时间
答案 0 :(得分:2)
返回POSIX
clock_gettime()
函数返回的时间。
以下是Time.now
times = Array.new(1000) { Time.now }
durations = times.each_cons(2).map { |a, b| b - a }
durations.sort.group_by(&:itself).each do |time, elements|
printf("%5d ns x %d\n", time * 1_000_000_000, elements.count)
end
输出:
0 ns x 686
1000 ns x 296
2000 ns x 12
3000 ns x 2
12000 ns x 2
18000 ns x 1
这是与Process.clock_gettime
相同的例子:
times = Array.new(1000) { Process.clock_gettime(Process::CLOCK_MONOTONIC) }
输出:
163 ns x 1
164 ns x 1
164 ns x 9
165 ns x 6
165 ns x 22
166 ns x 39
166 ns x 174
167 ns x 13
167 ns x 129
168 ns x 95
168 ns x 32
169 ns x 203
169 ns x 141
170 ns x 23
170 ns x 37
171 ns x 30
171 ns x 3
172 ns x 24
172 ns x 10
174 ns x 1
175 ns x 2
180 ns x 1
194 ns x 1
273 ns x 1
2565 ns x 1
这是一个快速的并排比较:
array = Array.new(12) { [Time.now, Process.clock_gettime(Process::CLOCK_MONOTONIC)] }
array.shift(2) # first elements are always inaccuate
base_t, base_p = array.first # baseline
printf("%-11.11s %-11.11s\n", 'Time.now', 'Process.clock_gettime')
array.each do |t, p|
printf("%.9f %.9f\n", t - base_t, p - base_p)
end
输出:
Time.now Process.clo
0.000000000 0.000000000
0.000000000 0.000000495
0.000001000 0.000000985
0.000001000 0.000001472
0.000002000 0.000001960
0.000002000 0.000002448
0.000003000 0.000002937
0.000003000 0.000003425
0.000004000 0.000003914
0.000004000 0.000004403
这是运行在Intel Core i7上的OS X上的Ruby 2.3,不确定Windows。
为避免浮点转换导致的精度损失,您可以指定其他单位,例如:
Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
#=> 191519383463873
答案 1 :(得分:1)
numTimes = 10000
times = Array.new(numTimes)
(0...(numTimes)).each do |i|
# nsec ⇓⇓⇓⇓
times[i] = Time.new.nsec
end
durations = (0...(numTimes - 1)).inject([]) do |memo, i|
memo << times[i+1] - times[i]
end
puts durations.reject(&:zero?).join $/
答案 2 :(得分:1)
Ruby Time objects存储自纪元以来的纳秒数。
从Ruby 1.9.2开始,Time实现使用带符号的63位整数,Bignum或Rational。整数是自Epoch以来的纳秒数,可以代表1823-11-12到2116-02-20。
您可以使用Time#nsec
最准确地访问纳秒部分。
$ ruby -e 't1 = Time.now; puts t1.to_f; puts t1.nsec'
1457079791.351686
351686000
正如您所看到的,在我的OS X机器上,它只能精确到微秒。这可能是因为OS X缺少clock_gettime()
。