Help us understand the problem. What is going on with this article?

【Go言語】 time.Time - t.Sub(u)はu→t の正確な経過時間を返さない(かもしれない)

問題

time.TimeのSubメソッドを利用すると、2つのtime.Time間のDurationを取得することが出来ます。

例えば↓なカンジで処理時間を計測したりします。

start := time.Now()

(何か処理)

elapsed := time.Now().Sub(start)

fmt.Println(elapsed)

このコード自体間違いではないですが、今回実行していて明らかに実際の経過時間を返していない事象に遭遇し、軽くハマりました。
9:02にスタートし9:10に終了しているのに、elapsedに 3m などと出力されたり。

startとnowも出力↓

start:2020-07-08 09:02:00.243095 +0900 JST m=+0.003321332
now:2020-07-08 09:10:25.388989 +0900 JST m=+222.388991487
elapsed:3m42.385670155s

startとnowも確かに正しい日時が入っています。何が起きているのでしょうか・・・ 🤔
(鋭い人はこのログでピンと来てそうですね)

タネあかし

ログを見ると m=+222.388991487 みたいな出力が見られます。
これの単位を秒とみなすと、nowとstartの差分がちょうどelapsedと一致します。

これは実はmonotonic clockと呼ばれるもので、time.Timeは時刻を表す情報(wall clock)とは別に時間計測に使う為の情報(monotonic clock)を持つことが出来ます。time.Now() で作成したtime.Timeは内部にmonotonic clockを持ちます。

Subメソッドの様な時間経過を得る為の関数1はwall clockよりmonotonic clockを優先的に使用して計算を行います。それにより、例えば処理中にOS時刻を変更されたりしても、正しく経過時間を取得することが出来ます。

さてここまで見る限り処理時間の計測方法としては正しいと思われる(実際正しい)のですが、なぜズレが生じてしまったのでしょうか。

公式ドキュメントにそのものズバり書かれていました(-ω-;
https://golang.org/pkg/time/#hdr-Monotonic_Clocks

On some systems the monotonic clock will stop if the computer goes to sleep. On such a system, t.Sub(u) may not accurately reflect the actual time that passed between t and u.

「いくつかのシステムではコンピューターがスリープした場合monoritic clockが停止して、t.Sub(u)が正しい経過時間を返さないことがある」とのことでした。

そうです。今回私は実行中に何度かスリープ→回復していたのです。2

明示的にwall clockで計算したい場合は、t.Sub(u)のt、uどちらかのmonotonic clock情報を削除すればOKです。
monotonic clock情報は t.Round(0) の様にすれば削除出来ます。

最後に

monotonic clockについては、今まで「時間計測に使用される」、「t.Timeを==演算子で比較するのは危険」くらいの曖昧な知識しかありませんでした。

time.Timeのドキュメント見ると真っ先にmonotonic clockの説明が書かれているのに、全然読んでませんでした(猛省)。
公式ドキュメントはちゃんと読まなきゃですね。。

参考にした記事


  1. 他にtime.Since(start)、time.Until(deadline)、time.Now().Before(deadline)などが同様にmonotonic clockを利用します。 

  2. 実行環境はMacBook Pro(macOC10.15.5)です。 

hogedigo
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away