[インデックス 1625] ファイルの概要
このコミットは、Go言語の標準ライブラリであるsrc/lib/http/triv.go
ファイルに対する変更です。このファイルは、GoのHTTPサーバー機能の基本的な使用方法や、Goの並行処理の概念(特にチャネル)をHTTPサーバーのコンテキストでどのように活用できるかを示すための、教育的な(pedagogical)目的を持つサンプルコードが含まれていると推測されます。具体的には、HTTPリクエストを処理する際にGoのチャネルを利用する新しいハンドラの実装が追加されています。
コミット
このコミットは、Rob Pikeによって2009年2月5日に作成されました。Go言語の初期段階における、チャネルがHTTPサーバーインターフェースを満たすことができるという、教育的なデモンストレーションを目的としています。src/lib/http/triv.go
ファイルに18行のコードが追加され、既存のコードの削除や変更はありません。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f95a11e27f8465435dd8a69ca6da67bbc6957270
元コミット内容
further pedagogy: a channel that satisfies the HTTP server interface
R=rsc
DELTA=18 (18 added, 0 deleted, 0 changed)
OCL=24482
CL=24484
変更の背景
この変更の背景には、Go言語の設計思想、特にその強力な並行処理プリミティブである「チャネル」の教育的な側面があります。Go言語は、CSP(Communicating Sequential Processes)に影響を受けた並行処理モデルを採用しており、ゴルーチン(goroutine)とチャネル(channel)を通じて、シンプルかつ効率的な並行プログラミングを可能にします。
このコミットの目的は、「チャネルがHTTPサーバーインターフェースを満たす」という概念を具体的に示すことにあります。これは、Goのインターフェースの柔軟性と、チャネルが単なるデータ転送メカニズムに留まらず、より抽象的な振る舞いを表現するための基盤となり得ることをデモンストレーションしています。HTTPサーバーのハンドラは通常、特定のインターフェース(http.Handler
)を実装することで機能しますが、このコミットでは、そのインターフェースをチャネル型が満たすようにすることで、HTTPリクエストの処理をチャネル操作と結びつけるユニークな例を提供しています。これは、Goの設計者が言語の機能と哲学をどのように教育し、普及させようとしていたかを示す一例と言えるでしょう。
前提知識の解説
このコミットの変更内容を理解するためには、以下のGo言語の基本的な概念と、net/http
パッケージに関する知識が必要です。
-
Go言語のゴルーチン (Goroutine): Go言語における軽量なスレッドのようなものです。
go
キーワードを関数呼び出しの前に置くことで、その関数を新しいゴルーチンとして実行し、他の処理と並行して動作させることができます。OSのスレッドよりもはるかに軽量で、数千、数万のゴルーチンを同時に実行することが可能です。 -
Go言語のチャネル (Channel): ゴルーチン間で値を送受信するための通信メカニズムです。チャネルは、ゴルーチン間の同期と通信を安全に行うための主要な手段であり、共有メモリによる競合状態(race condition)を避けるのに役立ちます。チャネルは
make(chan Type)
で作成され、ch <- value
で値を送信し、value := <-ch
で値を受信します。チャネルからの受信は、値が送信されるまでブロックされます。 -
net/http
パッケージ: Go言語の標準ライブラリで、HTTPクライアントとサーバーを実装するための機能を提供します。http.Handler
インターフェース: HTTPリクエストを処理するためのインターフェースです。このインターフェースは、ServeHTTP(ResponseWriter, *Request)
という単一のメソッドを定義しています。任意の型がこのメソッドを実装していれば、その型はhttp.Handler
インターフェースを満たしているとみなされ、HTTPリクエストハンドラとして登録できます。http.Handle(pattern string, handler Handler)
: 指定されたパスパターン(pattern
)に対するHTTPリクエストを処理するために、http.Handler
インターフェースを実装したhandler
を登録します。http.ListenAndServe(addr string, handler Handler)
: 指定されたアドレス(addr
)でHTTPサーバーを起動します。handler
がnil
の場合、デフォルトのhttp.DefaultServeMux
が使用されます。
-
Go言語のインターフェース: Go言語におけるインターフェースは、メソッドのシグネチャの集合です。型がインターフェースのすべてのメソッドを実装していれば、その型はそのインターフェースを満たしているとみなされます。Goのインターフェースは「暗黙的」であり、明示的に「このインターフェースを実装します」と宣言する必要はありません。
技術的詳細
このコミットの核心は、Goのチャネル型がhttp.Handler
インターフェースをどのように満たすかを示す点にあります。通常、HTTPハンドラは構造体や関数型として定義され、その上でServeHTTP
メソッドを実装します。しかし、この例では、Chan
という名前のchan int
型(整数のチャネル)を定義し、そのChan
型に対してServeHTTP
メソッドを実装しています。
具体的には、以下のステップでこのデモンストレーションが行われています。
-
Chan
型の定義:type Chan chan int
これにより、Chan
はint
型のチャネルのエイリアスとして定義されます。 -
ChanCreate
関数の実装:func ChanCreate() Chan
この関数は、新しいChan
(int
チャネル)を作成し、そのチャネルを返すとともに、新しいゴルーチンを起動します。このゴルーチンは無限ループで、x
というカウンタ変数を0からインクリメントし続け、その値をチャネルに送信し続けます(c <- x
)。これにより、チャネルは常に新しい整数値を生成し続ける「プロデューサー」となります。 -
Chan
型に対するServeHTTP
メソッドの実装:func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request)
これが最も重要な部分です。Chan
型がhttp.Handler
インターフェースを満たすために、このメソッドが実装されています。このメソッドが呼び出される(つまり、/chan
パスへのHTTPリクエストがあった)たびに、<-ch
という操作によってチャネルから値を受信します。チャネルからの受信は、値が利用可能になるまでブロックされます。受信した値は、fmt.Sprintf("channel send #%d\\n", <-ch)
によって文字列にフォーマットされ、io.WriteString(c, ...)
を通じてHTTPレスポンスとしてクライアントに書き込まれます。 -
HTTPハンドラとしての登録:
http.Handle("/chan", ChanCreate())
main
関数内で、/chan
というパスに対してChanCreate()
の戻り値(つまり、Chan
型のインスタンス)をハンドラとして登録しています。ChanCreate()
はチャネルを生成し、そのチャネルに値を送り続けるゴルーチンを起動するため、/chan
への各リクエストは、このチャネルから次の整数値を受け取り、それを表示することになります。
このアプローチの技術的な含意は、HTTPリクエストの処理が、Goの並行処理プリミティブであるチャネルの操作と直接結びついている点です。各リクエストはチャネルからの受信操作をトリガーし、これにより、複数のリクエストが同時に発生した場合でも、チャネルの同期メカニズムによって値が順番に(または、チャネルのバッファリング設定に応じて)処理されることが保証されます。これは、Goのインターフェースの柔軟性と、並行処理をアプリケーションロジックに自然に統合できるGoの能力を示す優れた例です。
コアとなるコードの変更箇所
diff --git a/src/lib/http/triv.go b/src/lib/http/triv.go
index 136100135a..3c527310ed 100644
--- a/src/lib/http/triv.go
+++ b/src/lib/http/triv.go
@@ -45,11 +45,29 @@ func FileServer(c *http.Conn, req *http.Request) {
fmt.Fprintf(c, "[%d bytes]\n", n);
}
+// a channel (just for the fun of it)
+type Chan chan int
+
+func ChanCreate() Chan {
+ c := make(Chan);
+ go func(c Chan) {
+ for x := 0;; x++ {
+ c <- x
+ }
+ }(c);
+ return c;
+}
+
+func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) {
+ io.WriteString(c, fmt.Sprintf("channel send #%d\n", <-ch));
+}
+
func main() {
flag.Parse();
http.Handle("/counter", new(Counter));
http.Handle("/go/", http.HandlerFunc(FileServer));
http.Handle("/go/hello", http.HandlerFunc(HelloServer));
+ http.Handle("/chan", ChanCreate());
err := http.ListenAndServe(":12345", nil);
if err != nil {
panic("ListenAndServe: ", err.String())
コアとなるコードの解説
追加されたコードは以下の3つの主要な部分と、main
関数でのその利用から構成されます。
-
type Chan chan int
: これは、Chan
という新しい型を定義しています。この型は、Goの組み込み型であるint
型のチャネル(chan int
)のエイリアスです。これにより、コード内でchan int
と書く代わりにChan
と書くことができ、可読性が向上します。 -
func ChanCreate() Chan
: この関数は、Chan
型の新しいチャネルを作成し、そのチャネルを返す役割を担います。c := make(Chan);
: 新しいint
チャネルc
を作成します。go func(c Chan) { ... }(c);
: ここが重要です。無名関数を新しいゴルーチンとして起動しています。このゴルーチンは、無限ループfor x := 0;; x++
の中で、変数x
を0から開始して1ずつインクリメントし、その値をチャネルc
に送信し続けます(c <- x
)。これにより、ChanCreate
が呼び出されるたびに、バックグラウンドでチャネルに整数値を供給し続ける独立した処理が開始されます。return c;
: 作成されたチャネルc
を返します。
-
func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request)
: このメソッドは、Chan
型がhttp.Handler
インターフェースを満たすために実装されています。Goのインターフェースは暗黙的に満たされるため、Chan
型がこのシグネチャのメソッドを持つことで、自動的にhttp.Handler
として扱えるようになります。io.WriteString(c, fmt.Sprintf("channel send #%d\n", <-ch));
: この行がHTTPリクエストの処理の核心です。<-ch
:ch
チャネルから値を受信します。ChanCreate
関数で起動されたゴルーチンがチャネルに値を送信しているため、ここで次の利用可能な整数値が取得されます。チャネルに値がない場合、この操作は値が送信されるまでブロックされます。fmt.Sprintf("channel send #%d\n", ...)
: 受信した整数値を「channel send #N」という形式の文字列にフォーマットします。io.WriteString(c, ...)
: フォーマットされた文字列をHTTPレスポンスとしてクライアントに書き込みます。c
はhttp.Conn
型であり、HTTPレスポンスを書き込むための接続を表します。
-
main
関数での利用:http.Handle("/chan", ChanCreate());
main
関数内で、/chan
というURLパスに対して、ChanCreate()
の戻り値(つまり、Chan
型のインスタンス)をHTTPハンドラとして登録しています。これにより、ユーザーがブラウザでhttp://localhost:12345/chan
にアクセスするたびに、Chan
インスタンスのServeHTTP
メソッドが呼び出され、チャネルから次の整数値が取得されて表示されます。
このコードは、Goのチャネルが単なるデータ転送だけでなく、HTTPリクエストのような外部イベントと内部の並行処理ロジックを連携させるための強力なメカニズムとして機能することを示しています。各リクエストがチャネルからの「次のアイテム」を取得するトリガーとなり、サーバーがリクエストごとにユニークな、順序付けられた応答を生成するシンプルな方法を提供します。
関連リンク
- Go言語公式ドキュメント: https://go.dev/doc/
- Go言語の並行処理 (Concurrency in Go): https://go.dev/tour/concurrency/1
net/http
パッケージドキュメント: https://pkg.go.dev/net/http- Go言語のインターフェース: https://go.dev/tour/methods/9
参考にした情報源リンク
- Go言語の公式ドキュメントおよびチュートリアル
- Go言語の並行処理に関する一般的な知識
net/http
パッケージの基本的な使用方法に関する知識- Go言語のインターフェースの概念に関する知識
- (必要に応じて)Go言語の初期のコミット履歴や設計に関する議論
[インデックス 1625] ファイルの概要
このコミットは、Go言語の標準ライブラリであるsrc/lib/http/triv.go
ファイルに対する変更です。このファイルは、GoのHTTPサーバー機能の基本的な使用方法や、Goの並行処理の概念(特にチャネル)をHTTPサーバーのコンテキストでどのように活用できるかを示すための、教育的な(pedagogical)目的を持つサンプルコードが含まれていると推測されます。具体的には、HTTPリクエストを処理する際にGoのチャネルを利用する新しいハンドラの実装が追加されています。
コミット
このコミットは、Rob Pikeによって2009年2月5日に作成されました。Go言語の初期段階における、チャネルがHTTPサーバーインターフェースを満たすことができるという、教育的なデモンストレーションを目的としています。src/lib/http/triv.go
ファイルに18行のコードが追加され、既存のコードの削除や変更はありません。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f95a11e27f8465435dd8a69ca6da67bbc6957270
元コミット内容
further pedagogy: a channel that satisfies the HTTP server interface
R=rsc
DELTA=18 (18 added, 0 deleted, 0 changed)
OCL=24482
CL=24484
変更の背景
この変更の背景には、Go言語の設計思想、特にその強力な並行処理プリミティブである「チャネル」の教育的な側面があります。Go言語は、CSP(Communicating Sequential Processes)に影響を受けた並行処理モデルを採用しており、ゴルーチン(goroutine)とチャネル(channel)を通じて、シンプルかつ効率的な並行プログラミングを可能にします。
このコミットの目的は、「チャネルがHTTPサーバーインターフェースを満たす」という概念を具体的に示すことにあります。これは、Goのインターフェースの柔軟性と、チャネルが単なるデータ転送メカニズムに留まらず、より抽象的な振る舞いを表現するための基盤となり得ることをデモンストレーションしています。HTTPサーバーのハンドラは通常、特定のインターフェース(http.Handler
)を実装することで機能しますが、このコミットでは、そのインターフェースをチャネル型が満たすようにすることで、HTTPリクエストの処理をチャネル操作と結びつけるユニークな例を提供しています。これは、Goの設計者が言語の機能と哲学をどのように教育し、普及させようとしていたかを示す一例と言えるでしょう。
前提知識の解説
このコミットの変更内容を理解するためには、以下のGo言語の基本的な概念と、net/http
パッケージに関する知識が必要です。
-
Go言語のゴルーチン (Goroutine): Go言語における軽量なスレッドのようなものです。
go
キーワードを関数呼び出しの前に置くことで、その関数を新しいゴルーチンとして実行し、他の処理と並行して動作させることができます。OSのスレッドよりもはるかに軽量で、数千、数万のゴルーチンを同時に実行することが可能です。 -
Go言語のチャネル (Channel): ゴルーチン間で値を送受信するための通信メカニズムです。チャネルは、ゴルーチン間の同期と通信を安全に行うための主要な手段であり、共有メモリによる競合状態(race condition)を避けるのに役立ちます。チャネルは
make(chan Type)
で作成され、ch <- value
で値を送信し、value := <-ch
で値を受信します。チャネルからの受信は、値が送信されるまでブロックされます。 -
net/http
パッケージ: Go言語の標準ライブラリで、HTTPクライアントとサーバーを実装するための機能を提供します。http.Handler
インターフェース: HTTPリクエストを処理するためのインターフェースです。このインターフェースは、ServeHTTP(ResponseWriter, *Request)
という単一のメソッドを定義しています。任意の型がこのメソッドを実装していれば、その型はhttp.Handler
インターフェースを満たしているとみなされ、HTTPリクエストハンドラとして登録できます。http.Handle(pattern string, handler Handler)
: 指定されたパスパターン(pattern
)に対するHTTPリクエストを処理するために、http.Handler
インターフェースを実装したhandler
を登録します。http.ListenAndServe(addr string, handler Handler)
: 指定されたアドレス(addr
)でHTTPサーバーを起動します。handler
がnil
の場合、デフォルトのhttp.DefaultServeMux
が使用されます。
-
Go言語のインターフェース: Go言語におけるインターフェースは、メソッドのシグネチャの集合です。型がインターフェースのすべてのメソッドを実装していれば、その型はそのインターフェースを満たしているとみなされます。Goのインターフェースは「暗黙的」であり、明示的に「このインターフェースを実装します」と宣言する必要はありません。
技術的詳細
このコミットの核心は、Goのチャネル型がhttp.Handler
インターフェースをどのように満たすかを示す点にあります。通常、HTTPハンドラは構造体や関数型として定義され、その上でServeHTTP
メソッドを実装します。しかし、この例では、Chan
という名前のchan int
型(整数のチャネル)を定義し、そのChan
型に対してServeHTTP
メソッドを実装しています。
具体的には、以下のステップでこのデモンストレーションが行われています。
-
Chan
型の定義:type Chan chan int
これにより、Chan
はint
型のチャネルのエイリアスとして定義されます。 -
ChanCreate
関数の実装:func ChanCreate() Chan
この関数は、新しいChan
(int
チャネル)を作成し、そのチャネルを返すとともに、新しいゴルーチンを起動します。このゴルーチンは無限ループで、x
というカウンタ変数を0からインクリメントし続け、その値をチャネルに送信し続けます(c <- x
)。これにより、チャネルは常に新しい整数値を生成し続ける「プロデューサー」となります。 -
Chan
型に対するServeHTTP
メソッドの実装:func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request)
これが最も重要な部分です。Chan
型がhttp.Handler
インターフェースを満たすために、このメソッドが実装されています。このメソッドが呼び出される(つまり、/chan
パスへのHTTPリクエストがあった)たびに、<-ch
という操作によってチャネルから値を受信します。ChanCreate
関数で起動されたゴルーチンがチャネルに値を送信しているため、ここで次の利用可能な整数値が取得されます。チャネルからの受信は、値が利用可能になるまでブロックされます。受信した値は、fmt.Sprintf("channel send #%d\\n", <-ch)
によって文字列にフォーマットされ、io.WriteString(c, ...)
を通じてHTTPレスポンスとしてクライアントに書き込まれます。 -
HTTPハンドラとしての登録:
http.Handle("/chan", ChanCreate())
main
関数内で、/chan
というパスに対してChanCreate()
の戻り値(つまり、Chan
型のインスタンス)をハンドラとして登録しています。ChanCreate()
はチャネルを生成し、そのチャネルに値を送り続けるゴルーチンを起動するため、/chan
への各リクエストは、このチャネルから次の整数値を受け取り、それを表示することになります。
このアプローチの技術的な含意は、HTTPリクエストの処理が、Goの並行処理プリミティブであるチャネルの操作と直接結びついている点です。各リクエストはチャネルからの受信操作をトリガーし、これにより、複数のリクエストが同時に発生した場合でも、チャネルの同期メカニズムによって値が順番に(または、チャネルのバッファリング設定に応じて)処理されることが保証されます。これは、Goのインターフェースの柔軟性と、並行処理をアプリケーションロジックに自然に統合できるGoの能力を示す優れた例です。
コアとなるコードの変更箇所
diff --git a/src/lib/http/triv.go b/src/lib/http/triv.go
index 136100135a..3c527310ed 100644
--- a/src/lib/http/triv.go
+++ b/src/lib/http/triv.go
@@ -45,11 +45,29 @@ func FileServer(c *http.Conn, req *http.Request) {
fmt.Fprintf(c, "[%d bytes]\n", n);
}
+// a channel (just for the fun of it)
+type Chan chan int
+
+func ChanCreate() Chan {
+ c := make(Chan);
+ go func(c Chan) {
+ for x := 0;; x++ {
+ c <- x
+ }
+ }(c);
+ return c;
+}
+
+func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) {
+ io.WriteString(c, fmt.Sprintf("channel send #%d\n", <-ch));
+}
+
func main() {
flag.Parse();
http.Handle("/counter", new(Counter));
http.Handle("/go/", http.HandlerFunc(FileServer));
http.Handle("/go/hello", http.HandlerFunc(HelloServer));
+ http.Handle("/chan", ChanCreate());
err := http.ListenAndServe(":12345", nil);
if err != nil {
panic("ListenAndServe: ", err.String())
コアとなるコードの解説
追加されたコードは以下の3つの主要な部分と、main
関数でのその利用から構成されます。
-
type Chan chan int
: これは、Chan
という新しい型を定義しています。この型は、Goの組み込み型であるint
型のチャネル(chan int
)のエイリアスです。これにより、コード内でchan int
と書く代わりにChan
と書くことができ、可読性が向上します。 -
func ChanCreate() Chan
: この関数は、Chan
型の新しいチャネルを作成し、そのチャネルを返す役割を担います。c := make(Chan);
: 新しいint
チャネルc
を作成します。go func(c Chan) { ... }(c);
: ここが重要です。無名関数を新しいゴルーチンとして起動しています。このゴルーチンは、無限ループfor x := 0;; x++
の中で、変数x
を0から開始して1ずつインクリメントし、その値をチャネルc
に送信し続けます(c <- x
)。これにより、ChanCreate
が呼び出されるたびに、バックグラウンドでチャネルに整数値を供給し続ける独立した処理が開始されます。return c;
: 作成されたチャネルc
を返します。
-
func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request)
: このメソッドは、Chan
型がhttp.Handler
インターフェースを満たすために実装されています。Goのインターフェースは暗黙的に満たされるため、Chan
型がこのシグネチャのメソッドを持つことで、自動的にhttp.Handler
として扱えるようになります。io.WriteString(c, fmt.Sprintf("channel send #%d\n", <-ch));
: この行がHTTPリクエストの処理の核心です。<-ch
:ch
チャネルから値を受信します。ChanCreate
関数で起動されたゴルーチンがチャネルに値を送信しているため、ここで次の利用可能な整数値が取得されます。チャネルに値がない場合、この操作は値が送信されるまでブロックされます。fmt.Sprintf("channel send #%d\n", ...)
: 受信した整数値を「channel send #N」という形式の文字列にフォーマットします。io.WriteString(c, ...)
: フォーマットされた文字列をHTTPレスポンスとしてクライアントに書き込みます。c
はhttp.Conn
型であり、HTTPレスポンスを書き込むための接続を表します。
-
main
関数での利用:http.Handle("/chan", ChanCreate());
main
関数内で、/chan
というURLパスに対して、ChanCreate()
の戻り値(つまり、Chan
型のインスタンス)をHTTPハンドラとして登録しています。これにより、ユーザーがブラウザでhttp://localhost:12345/chan
にアクセスするたびに、Chan
インスタンスのServeHTTP
メソッドが呼び出され、チャネルから次の整数値が取得されて表示されます。
このコードは、Goのチャネルが単なるデータ転送だけでなく、HTTPリクエストのような外部イベントと内部の並行処理ロジックを連携させるための強力なメカニズムとして機能することを示しています。各リクエストがチャネルからの「次のアイテム」を取得するトリガーとなり、サーバーがリクエストごとにユニークな、順序付けられた応答を生成するシンプルな方法を提供します。
関連リンク
- Go言語公式ドキュメント: https://go.dev/doc/
- Go言語の並行処理 (Concurrency in Go): https://go.dev/tour/concurrency/1
net/http
パッケージドキュメント: https://pkg.go.dev/net/http- Go言語のインターフェース: https://go.dev/tour/methods/9
参考にした情報源リンク
- Go言語の公式ドキュメントおよびチュートリアル
- Go言語の並行処理に関する一般的な知識
net/http
パッケージの基本的な使用方法に関する知識- Go言語のインターフェースの概念に関する知識
- Go言語の初期のコミット履歴や設計に関する議論
- Web検索: "Go language early http server examples channels"