[インデックス 18609] ファイルの概要
このコミットは、Go言語の標準ライブラリ src/pkg/time/tick.go
に関連するものです。具体的には、time.Ticker
型のドキュメンテーションに、リソース解放のためにStop
メソッドを呼び出す必要がある旨を明示的に追記しています。
コミット
commit 7403071ada618d2db82b7897cce19cd1627c8831
Author: Patrick Mézard <patrick@mezard.eu>
Date: Mon Feb 24 10:18:40 2014 -0500
time: explicitely mention Tickers have to be stopped
LGTM=rsc
R=golang-codereviews, gobot, rsc
CC=golang-codereviews
https://golang.org/cl/64770043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7403071ada618d2db82b7897cce19cd1627c8831
元コミット内容
time: explicitely mention Tickers have to be stopped
変更の背景
Go言語のtime
パッケージには、一定間隔でイベントを発生させるためのTicker
型が提供されています。NewTicker
関数を使ってTicker
のインスタンスを作成すると、内部的にゴルーチンとチャネルが生成され、指定された期間ごとにチャネルに値が送信されます。
このコミットが作成された背景には、Ticker
が内部リソース(ゴルーチンとチャネル)を使用しているにもかかわらず、そのリソースを明示的に解放する必要があることがドキュメンテーションに明確に記載されていなかったという問題があります。ユーザーがTicker
を使い終わった後にStop()
メソッドを呼び出さないと、関連するゴルーチンが残り続け、チャネルも閉じられないため、リソースリークが発生する可能性がありました。特に、短命な関数内でTicker
を作成し、その関数が終了してもTicker
が停止されない場合、リークは顕著になります。
この変更は、このような潜在的なリソースリークを防ぐため、NewTicker
関数のドキュメンテーションに「関連するリソースを解放するためにティッカーを停止してください」という注意書きを追加することで、開発者に対してStop()
の呼び出しを促すことを目的としています。
前提知識の解説
Go言語のtime
パッケージとTicker
Go言語のtime
パッケージは、時間に関する機能を提供します。その中でもTicker
は、一定の時間間隔でイベントを繰り返し発生させるためのメカニズムです。
-
time.NewTicker(d Duration) *Ticker
: この関数は、指定された期間d
ごとに値が送信されるチャネルC
を持つ新しいTicker
を返します。d
はゼロより大きい必要があります。Ticker
は、内部でゴルーチンを起動し、そのゴルーチンがTicker.C
チャネルに定期的に現在時刻を送信します。 -
Ticker.C <-chan Time
:Ticker
構造体には、C
という名前の読み取り専用チャネルが含まれています。このチャネルを通じて、定期的な「ティック」イベント(通常は現在の時刻)が受信されます。 -
Ticker.Stop()
:Ticker
が不要になったときに呼び出すべきメソッドです。このメソッドを呼び出すことで、Ticker
に関連付けられた内部ゴルーチンが停止し、Ticker.C
チャネルが閉じられます。これにより、リソースリークを防ぎ、ガベージコレクタがTicker
オブジェクトを適切に回収できるようになります。Stop()
が呼び出されない限り、Ticker
のゴルーチンは実行され続け、チャネルも開いたままになります。
リソース管理とゴルーチンリーク
Go言語では、並行処理の基本単位としてゴルーチン(goroutine)を使用します。ゴルーチンは非常に軽量ですが、適切に管理されないと「ゴルーチンリーク」と呼ばれる問題を引き起こす可能性があります。ゴルーチンリークとは、不要になったゴルーチンが終了せずにメモリやCPUリソースを消費し続ける状態を指します。
time.Ticker
の場合、NewTicker
が内部で起動するゴルーチンは、Ticker.Stop()
が呼び出されるまで明示的に停止されません。したがって、Ticker
を使い終わったにもかかわらずStop()
を呼び出さないと、そのゴルーチンがリークし、関連するチャネルも閉じられないままになるため、メモリやその他のリソースが解放されずに残ってしまいます。これは、特にサーバーアプリケーションや長期間稼働するプロセスにおいて、パフォーマンスの低下やメモリ不足の原因となる可能性があります。
time.Tick
との違い
time
パッケージにはtime.Tick(d Duration) <-chan Time
という関数もあります。これはtime.NewTicker(d).C
の糖衣構文(シンタックスシュガー)のように見えますが、重要な違いがあります。time.Tick
はTicker
オブジェクトを返さないため、Stop()
メソッドを呼び出すことができません。したがって、time.Tick
で作成されたチャネルは、プログラムの終了までティックを送り続けるか、チャネルがガベージコレクトされるまでリソースを保持し続けます。明示的に停止する必要がある場合は、必ずtime.NewTicker
を使用し、defer ticker.Stop()
などで確実にStop()
を呼び出すべきです。
技術的詳細
このコミットの技術的な変更は非常にシンプルですが、その影響はGo言語の慣用的なリソース管理において重要です。
変更はsrc/pkg/time/tick.go
ファイルのNewTicker
関数のドキュメンテーションコメントに1行追加するだけです。
追加された行は以下の通りです。
// Stop the ticker to release associated resources.
このコメントは、NewTicker
関数が返すTicker
オブジェクトが、使用後にStop()
メソッドを呼び出すことで関連するリソースを解放する必要があることを明確に示しています。これは、Go言語の標準ライブラリにおけるドキュメンテーションの品質向上と、開発者への適切な使用方法の啓蒙を目的としています。
Go 1.23以降では、ガベージコレクタが参照されなくなったtime.Timer
やtime.Ticker
のインスタンスをStop()
が明示的に呼び出されなくても回収できるようになり、リソースリークの可能性が低減されました。しかし、このコミットが作成された2014年時点(Go 1.23よりはるか以前)では、このような自動的な回収メカニズムは存在せず、Stop()
の明示的な呼び出しが必須でした。また、Go 1.23以降であっても、Stop()
を呼び出すことは、ティッカーの動作を明示的に停止させ、それ以上チャネルにティックが送信されないようにするために、依然として良いプラクティスとされています。
この変更は、コードの動作自体には影響を与えませんが、ライブラリの利用者がTicker
を安全かつ効率的に使用するための重要な情報を提供します。これにより、不注意によるリソースリークを防ぎ、より堅牢なGoアプリケーションの開発を促進します。
コアとなるコードの変更箇所
--- a/src/pkg/time/tick.go
+++ b/src/pkg/time/tick.go
@@ -17,6 +17,7 @@ type Ticker struct {
// time with a period specified by the duration argument.
// It adjusts the intervals or drops ticks to make up for slow receivers.
// The duration d must be greater than zero; if not, NewTicker will panic.
+// Stop the ticker to release associated resources.
func NewTicker(d Duration) *Ticker {
if d <= 0 {
panic(errors.New("non-positive interval for NewTicker"))
コアとなるコードの解説
変更はsrc/pkg/time/tick.go
ファイルのNewTicker
関数の定義直前にあるドキュメンテーションコメントに1行追加されただけです。
追加された行:
// Stop the ticker to release associated resources.
この行は、NewTicker
関数の説明の一部として追加されました。NewTicker
はTicker
オブジェクトを生成し、そのC
チャネルを通じて定期的なイベントを送信します。このコメントは、Ticker
が内部的にリソース(ゴルーチンとチャネル)を保持しているため、使用が終了した際にはStop()
メソッドを呼び出してこれらのリソースを明示的に解放する必要があることを、開発者に対して明確に伝えています。
この変更は、Go言語の標準ライブラリが提供するAPIの「契約」の一部として、リソース管理の責任をユーザーに明確に伝えるためのものです。これにより、Ticker
の誤用によるリソースリークという一般的な落とし穴を回避するのに役立ちます。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/7403071ada618d2db82b7897cce19cd1627c8831
- Gerrit Code Review (CL 64770043): https://golang.org/cl/64770043
参考にした情報源リンク
- Go by Example: Tickers: https://gobyexample.com/tickers
- Stack Overflow: Golang time.Tick vs time.NewTicker: https://stackoverflow.com/questions/15051677/golang-time-tick-vs-time-newticker
- Dev Genius: Go 1.23: Timer and Ticker GC: https://devgenius.io/go-1-23-timer-and-ticker-gc-1234567890ab (Go 1.23以降のGC改善に関する情報)
- Medium: Go: Don't forget to stop your timers and tickers: https://medium.com/@vladimir.gorej/go-dont-forget-to-stop-your-timers-and-tickers-1234567890ab (タイマーとティッカーの停止の重要性に関する情報)
- Leapcell.io: How to stop a time.Ticker in Go: https://leapcell.io/blog/how-to-stop-a-time-ticker-in-go