はじめに
こんにちは!アメリカの大学で語学を学びながら、独学でソフトウェアエンジニアを目指している者です。
今日は Ruby の Time
クラスで Time.now
と sleep
を使った場合に生じる意外な誤差について解説します。このテーマは、一見すると「時間計測にズレが生じているのは、Time.now
を処理する時間だから?」と誤解しやすく、とても興味深い話題です。私自身も最初はそう思ったのですが、実際には異なる原因があるようです。詳しく見ていきましょう。
コード例とその疑問
まずは以下のコードを見てください。
t1 = Time.now
sleep 10
t2 = Time.now
p t1 < t2 # => true
p t2 - t1 # => 10.012828
ここで疑問になるのは、「t2 - t1
の結果がちょうど10秒ではなく、10.012828
のように誤差があるのはなぜなのか?」という点です。
私も最初は「この誤差は Time.now
の処理にかかる時間なのか?」と思いましたが、実はそうではないようです。この誤差の主な原因について詳しく解説します。
誤差の主な原因
1. sleep
の精度
Rubyのsleep
メソッドは、指定した秒数だけスレッドを停止させますが、この停止が完全に正確に行われるわけではありません。sleep
の実行時間には、以下のような要因でわずかな誤差が生じます。
- オペレーティングシステムのスケジューリング:OSがプロセスのスケジューリングを行う際、処理の順番やタイミングが影響することがあります。そのため、厳密に10秒のスリープであっても、若干の遅延が発生することがあります。
- プロセス切り替えの時間:スリープ終了時に、他のプロセスからRubyプロセスに戻るまでのタイムラグがわずかに生じることがあります。
これらの理由から、sleep 10
の後に計測した時間差が「10秒ぴったり」ではなく、10.012828
のように少し長くなることがあります。つまり、今回の誤差の主な原因は、sleep
の精度によるものです。
2. Time.now
の精度
もう一つの要因として、Time.now
の精度も関係しています。Time.now
は高精度で現在時刻を取得しますが、そのタイミングによって微小なズレが生じることがあります。このズレは非常に短いため、通常は無視できる程度のものですが、sleep
による誤差と組み合わさると、結果として数ミリ秒の誤差が生じることがあります。
Time.now
の処理時間を計測するには?
Time.now
の処理にどれくらい時間がかかるのか?を実際に測定したい場合、Benchmark
ライブラリを使うことで計測できます。
require 'benchmark'
execution_time = Benchmark.realtime do
Time.now
end
puts "Time.nowの処理時間: #{execution_time}秒"
出力例(環境に依存しますが非常に小さい値になるはずです):
Time.nowの処理時間: 0.000005秒
この結果から、Time.now
の処理時間はほぼ無視できるほど短く、今回の誤差に影響していないことがわかります。
まとめ
今回のコード例では、t2 - t1
の結果に含まれる誤差は、主にsleep
メソッドの精度とOSのスケジューリングによるものであり、Time.now
の処理時間が主な原因ではありません。sleep
の仕様により、指定した時間に対してわずかなズレが発生することがあるため、この点を理解しておくことが重要です。
Rubyで時間を扱う際には、このような微妙な誤差が生じる可能性があることを念頭に置き、必要に応じて適切に対処することが求められます。例えば、非常に正確な時間計測が必要な場合には、Benchmark
ライブラリを使うことが推奨されます。