📝

Goのtime packageによるwall clockとmonotonic clockについて

2023/07/22に公開

wall clockmonotoric clockとは

現代のコンピューターには少なくとも2つの時間が存在します。1つは時刻の時間(wall clock)で、もう1つが短調増加の時間(monotonic clock)です。
wall clockとはカレンダーに基づいた現在の日付、時刻を指します。一方で、monotonic clockは常に進み続ける時間を指します(ストップウォッチなどイメージしやすいです)。
wall clockは通常NTPサーバーと同期されています。これはすなわち、あるマシン上のタイムスタンプは、他のマシン上のタイムスタンプと同じ時刻を指すということです。
monotonic clockはある時間を起点として時間を短調増加させたものです。(ストップウォッチなら0秒を起点として時間が増えていく)
wall clockは現在日時がいつなのか調べることに向いており、monotonic clockは期間を調べることに向いています。
Goでも1.9からこのmonotonic clockがサポートされるようになりました。

time packageのwall clockmonotonic clock

Goのtime packageはTime構造体を返しますが、この構造体にwall clockmonotonic clockが含まれています。
現在時刻を取得するために以下を実行することが多いかと思います。

time.Now()

こちらはTime構造体を返します。
Time構造体にDurationをAdd()してみましょう。

t0 := time.Now()               // 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
t1 := t0.Add(10 * time.minute) // 2009-11-10 23:10:00 +0000 UTC m=+600.000000001

そうすると、現在時刻よりも 10分進んだ別のTime構造体を得ることができます。
ここで、t0やt1で表示された時間を見てください。横にm = +hogehogeと表示されています。
これがGoでのmonotonic clockです。また、それ以前の時刻を表しているのがwall clock です。

time packageのドキュメントにも以下のように書かれています。

If the time has a monotonic clock reading, the returned string includes a final field “m=±<value>”, where value is the monotonic clock reading formatted as a decimal number of seconds.

ここで、m=+0.000000001が気になった方もいるかもしれません。これは、プログラムが実行するのにかかった時間なのであまり気にしないでください。

ここで2つの時間の差分を見てみます。

t2 := t1.Sub(t0) // 10m0s

追加した時間だけの差分が表示されました。この差分はmonotonic clockに基づいて計算されています。

しかし、monotonic clockはいつでも利用できるわけではありません。monotonic clockが消えてしまうメソッド(AddDate, Round, Truncateなど)がいくつか存在します。

t3 := t0.Round(0) // 2009-11-10 23:00:00 +0000 UTC

このようにmonotonic clockが消えた状態でSubメソッドを実行するとmonotonick clockの代わりにwall clockで処理が実行されるので気をつけましょう。公式ドキュメントにも以下のように書かれています。

If Times t and u both contain monotonic clock readings, the operations t.After(u), t.Before(u), t.Equal(u), t.Compare(u), and t.Sub(u) are carried out using the monotonic clock readings alone, ignoring the wall clock readings. If either t or u contains no monotonic clock reading, these operations fall back to using the wall clock readings.

まとめ

Goのwall clockmonotonic clockについて解説しました。時刻を調べる時にはwall clockを使い、期間を調べる時にはmonotonic clockが使用されています。Time構造体に実装されているメソッドにはmonotonic clockを消してしまうメソッドも存在するので気を付けましょう。

Discussion