[インデックス 12121] ファイルの概要
このコミットは、Go言語の標準ライブラリ net/http
パッケージ内のテストコード serve_test.go
における time.Duration
の使用方法を改善するものです。具体的には、タイムアウト設定の記述をよりGoらしい慣用的な形式に変更しています。
コミット
- コミットハッシュ:
9c8923f7dc4b983dca233085560adf4dc079dc25
- Author: Brad Fitzpatrick bradfitz@golang.org
- Date: Wed Feb 22 11:22:09 2012 +1100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9c8923f7dc4b983dca233085560adf4dc079dc25
元コミット内容
net/http: update test to use time.Duration better
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5688063
変更の背景
このコミットの背景には、Go言語における時間単位の表現のベストプラクティスへの準拠があります。Goの time
パッケージは、時間量を扱うための time.Duration
型を提供しており、これはナノ秒単位の整数として時間を表現します。この型は、可読性と型安全性を高めるために、time.Second
や time.Millisecond
といった定数と組み合わせて使用することが推奨されています。
元のコードでは、const second = 1000000000 /* nanos */
のように、ナノ秒を直接整数で定義し、それを浮動小数点数で乗算してタイムアウト値を設定していました。これは機能的には問題ありませんが、Goの慣用的な書き方ではありませんでした。time.Duration
を直接使用することで、コードの意図がより明確になり、将来的なメンテナンス性や可読性が向上します。また、浮動小数点数演算による潜在的な精度問題も回避できます。
前提知識の解説
Go言語の time
パッケージと time.Duration
Go言語の time
パッケージは、時間と日付を扱うための強力な機能を提供します。その中でも time.Duration
型は、時間の長さを表現するために設計された型です。これは int64
のエイリアスであり、ナノ秒単位で時間を内部的に保持します。
time.Duration
は、以下のような時間単位の定数と組み合わせて使用することで、非常に可読性の高いコードを書くことができます。
time.Nanosecond
time.Microsecond
time.Millisecond
time.Second
time.Minute
time.Hour
例えば、5秒間は 5 * time.Second
と記述でき、250ミリ秒は 250 * time.Millisecond
と記述できます。これにより、コードを読むだけでその数値が何を意味するのかが直感的に理解できます。
net/http
パッケージと http.Server
のタイムアウト設定
net/http
パッケージは、HTTPクライアントとサーバーの実装を提供します。HTTPサーバーを構築する際に使用する http.Server
構造体には、クライアントからのリクエスト処理におけるタイムアウトを設定するためのフィールドがあります。
ReadTimeout
: クライアントがリクエストヘッダーとボディを送信するのにかかる時間の最大値。この時間を超えると、サーバーは接続を閉じます。WriteTimeout
: サーバーがレスポンスヘッダーとボディをクライアントに送信するのにかかる時間の最大値。この時間を超えると、サーバーは接続を閉じます。
これらのタイムアウトは、サービス拒否(DoS)攻撃を防いだり、リソースの枯渇を避けたりするために重要です。これらのフィールドは time.Duration
型を受け取ります。
技術的詳細
このコミットは、src/pkg/net/http/serve_test.go
ファイル内の TestServerTimeouts
関数における http.Server
のタイムアウト設定方法を変更しています。
変更前は、以下のように second
という定数を定義し、それを使ってタイムアウト値を計算していました。
const second = 1000000000 /* nanos */
server := &Server{Handler: handler, ReadTimeout: 0.25 * second, WriteTimeout: 0.25 * second}
ここで 0.25 * second
は、浮動小数点数 0.25
と整数 1000000000
の乗算であり、結果は 250000000
となります。これはナノ秒単位で250ミリ秒を意味します。
変更後は、Goの time
パッケージが提供する time.Millisecond
定数を直接使用するように修正されました。
server := &Server{Handler: handler, ReadTimeout: 250 * time.Millisecond, WriteTimeout: 250 * time.Millisecond}
この変更により、コードの意図がより明確になり、ReadTimeout
と WriteTimeout
がそれぞれ250ミリ秒であることを一目で理解できるようになりました。また、コメントの /* fudge from 0.25 above */
も /* fudge from 250 ms above */
に更新され、整合性が保たれています。
この変更は、Goの慣用的なコーディングスタイルに準拠し、コードの可読性と保守性を向上させるためのものです。機能的な変更はなく、テストの動作に影響はありません。
コアとなるコードの変更箇所
--- a/src/pkg/net/http/serve_test.go
+++ b/src/pkg/net/http/serve_test.go
@@ -245,8 +245,7 @@ func TestServerTimeouts(t *testing.T) {
fmt.Fprintf(res, "req=%d", reqNum)
})
- const second = 1000000000 /* nanos */
- server := &Server{Handler: handler, ReadTimeout: 0.25 * second, WriteTimeout: 0.25 * second}
+ server := &Server{Handler: handler, ReadTimeout: 250 * time.Millisecond, WriteTimeout: 250 * time.Millisecond}
go server.Serve(l)
url := fmt.Sprintf("http://%s/", addr)
@@ -277,7 +276,7 @@ func TestServerTimeouts(t *testing.T) {
if n != 0 || err != io.EOF {
t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
}
- if latency < 200*time.Millisecond /* fudge from 0.25 above */ {
+ if latency < 200*time.Millisecond /* fudge from 250 ms above */ {
t.Errorf("got EOF after %s, want >= %s", latency, 200*time.Millisecond)
}
コアとなるコードの解説
変更点1: const second
の削除と ReadTimeout
/WriteTimeout
の設定変更
- const second = 1000000000 /* nanos */
- server := &Server{Handler: handler, ReadTimeout: 0.25 * second, WriteTimeout: 0.25 * second}
+ server := &Server{Handler: handler, ReadTimeout: 250 * time.Millisecond, WriteTimeout: 250 * time.Millisecond}
- 削除された行:
const second = 1000000000 /* nanos */
- この行は、1秒をナノ秒で定義する定数でした。Goの
time
パッケージが提供するtime.Second
やtime.Millisecond
といった定数を使用すれば、このような手動での定義は不要です。
- この行は、1秒をナノ秒で定義する定数でした。Goの
- 変更された行:
server := &Server{Handler: handler, ReadTimeout: 250 * time.Millisecond, WriteTimeout: 250 * time.Millisecond}
ReadTimeout
とWriteTimeout
の値が、0.25 * second
から250 * time.Millisecond
に変更されました。250 * time.Millisecond
は、time.Duration
型の値を生成するGoの慣用的な方法です。これにより、250ミリ秒という時間の長さが明確に表現されます。- この変更により、コードの可読性が大幅に向上し、数値が何を意味するのかが直感的に理解できるようになります。
変更点2: コメントの更新
- if latency < 200*time.Millisecond /* fudge from 0.25 above */ {
+ if latency < 200*time.Millisecond /* fudge from 250 ms above */ {
- 変更された行:
if latency < 200*time.Millisecond /* fudge from 250 ms above */ {
- コメント
/* fudge from 0.25 above */
が/* fudge from 250 ms above */
に更新されました。 - これは、タイムアウト値の計算が
0.25 * second
ではなく250 * time.Millisecond
に基づいていることを反映しています。 - このコメントの更新は、コードの変更と整合性を保ち、読者がコードの意図を正しく理解できるようにするために重要です。
- コメント
これらの変更は、Goのコーディング規約とベストプラクティスに沿ったものであり、コードの品質と保守性を向上させます。
関連リンク
- Go CL 5688063: https://golang.org/cl/5688063
参考にした情報源リンク
- Go Documentation:
time
package: https://pkg.go.dev/time - Go Documentation:
net/http
package: https://pkg.go.dev/net/http - Go by Example: Timers: https://gobyexample.com/timers (General understanding of
time.Duration
)