我在Rubymine 8.0.3中运行Ruby2.2
我的计算机运行的是带有英特尔酷睿i7-4710MQ的Windows 7专业版
我已经能够在这台机器上用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微秒的刻度之间的持续时间
发布于 2016-03-04 18:37:44
使用Process::clock_gettime可以获得更高的精度
返回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这是在英特尔酷睿i7上运行的OS X上的Ruby2.3,对Windows不太确定。
为了避免浮点转换造成的精度损失,您可以指定另一个单位,例如:
Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
#=> 191519383463873发布于 2016-03-04 16:36:43
Time#nsec
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 $/发布于 2016-03-04 16:36:59
Ruby Time objects存储从纪元开始的纳秒数。
从Ruby1.9.2开始,Time实现使用带符号的63位整数,即Bignum或Rational。该整数是从纪元开始的纳秒数,可以表示1823-11-12到2116-02-20。
您可以使用Time#nsec最精确地访问纳秒部分。
$ ruby -e 't1 = Time.now; puts t1.to_f; puts t1.nsec'
1457079791.351686
351686000如你所见,在我的OS机器上,它只能精确到微秒级。这可能是因为OS没有clock_gettime()。
https://stackoverflow.com/questions/35790966
复制相似问题