Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 17582] ファイルの概要

このコミットは、Go言語の net/rpc パッケージにおいて、ClientCodec および ServerCodec インターフェースの実装におけるスレッドセーフティ要件を明確にするためのドキュメント追加です。具体的には、ClientCodec.WriteRequest メソッドと ServerCodec.WriteResponse メソッドが複数のゴルーチンから同時に安全に利用できる必要があることを明記しています。

コミット

  • コミットハッシュ: 1e71e7426210fd5544bee462240c666c7277327e
  • Author: Han-Wen Nienhuys hanwen@google.com
  • Date: Thu Sep 12 22:03:53 2013 +1000

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/1e71e7426210fd5544bee462240c666c7277327e

元コミット内容

net/rpc: document thread safety requirements of codec types.

Fixes #6306.

R=golang-dev, bradfitz, r
CC=golang-dev
https://golang.org/cl/13474043

変更の背景

この変更は、GoのIssue #6306 に対応するものです。Issue #6306では、net/rpc パッケージの ClientCodec および ServerCodec の実装が、複数のゴルーチンから同時に呼び出された場合にスレッドセーフであるべきかどうかが不明確であるという問題が提起されていました。

net/rpc パッケージは、Goアプリケーション間でリモートプロシージャコール(RPC)を行うためのメカニズムを提供します。クライアントとサーバーは、データのエンコードとデコードを行うために Codec インターフェース(ClientCodecServerCodec)の実装を使用します。

既存のドキュメントでは、これらの Codec メソッドが並行して呼び出された場合にどのように振る舞うべきかについて明示的な記述がありませんでした。この曖昧さにより、Codec のカスタム実装を作成する開発者が、意図せずスレッドセーフではないコードを書いてしまう可能性がありました。特に、WriteRequestWriteResponse のような書き込み操作は、共有リソース(例えばネットワーク接続)にアクセスするため、並行アクセスに対して保護される必要があります。

このコミットは、この曖昧さを解消し、Codec の実装者が安全なコードを書けるように、スレッドセーフティの要件を明示的にドキュメントに追加することを目的としています。

前提知識の解説

Goの net/rpc パッケージ

net/rpc パッケージは、Goプログラムがネットワーク経由で他のGoプログラムの関数を呼び出すためのメカニズムを提供します。これは、クライアント/サーバーモデルに基づいており、クライアントはリモートサーバー上のメソッドを呼び出し、サーバーはその呼び出しを処理して結果を返します。

  • Client: RPCクライアントを表します。リモートサーバーへの接続を管理し、リモートメソッド呼び出しをディスパッチします。
  • Server: RPCサーバーを表します。クライアントからのリクエストを受け入れ、登録されたサービスメソッドを呼び出します。
  • Codec (ClientCodec/ServerCodec): RPCメッセージのエンコード(Goのデータ構造からバイトストリームへ)とデコード(バイトストリームからGoのデータ構造へ)を担当するインターフェースです。これにより、JSON、Gob、Protobufなど、さまざまなデータフォーマットをRPCで使用できます。

ClientCodec インターフェース

ClientCodec インターフェースは、クライアント側でのRPCメッセージのエンコードとデコードを定義します。

type ClientCodec interface {
	WriteRequest(*Request, interface{}) error
	ReadResponseHeader(*Response) error
	ReadResponseBody(interface{}) error
	Close() error
}
  • WriteRequest: クライアントのリクエスト(メソッド名、引数など)をエンコードし、ネットワークに書き込みます。
  • ReadResponseHeader: サーバーからの応答ヘッダーを読み込み、デコードします。
  • ReadResponseBody: サーバーからの応答ボディ(結果)を読み込み、デコードします。
  • Close: コネクションを閉じます。

ServerCodec インターフェース

ServerCodec インターフェースは、サーバー側でのRPCメッセージのエンコードとデコードを定義します。

type ServerCodec interface {
	ReadRequestHeader(*Request) error
	ReadRequestBody(interface{}) error
	WriteResponse(*Response, interface{}) error
	Close() error
}
  • ReadRequestHeader: クライアントからのリクエストヘッダーを読み込み、デコードします。
  • ReadRequestBody: クライアントからのリクエストボディ(引数)を読み込み、デコードします。
  • WriteResponse: サーバーの応答(結果、エラーなど)をエンコードし、ネットワークに書き込みます。
  • Close: コネクションを閉じます。

ゴルーチンと並行性

Go言語は、軽量な実行スレッドである「ゴルーチン(goroutine)」を使用して並行処理をサポートします。複数のゴルーチンが同時に実行され、共有リソースにアクセスする可能性があります。

スレッドセーフティ

スレッドセーフティとは、複数のスレッド(Goの場合はゴルーチン)から同時にアクセスされた場合でも、データ構造やプログラムが正しく動作することを保証する特性です。共有リソースへの書き込み操作は、競合状態(race condition)を避けるために通常、ミューテックス(sync.Mutex)などの同期プリミティブによって保護される必要があります。

技術的詳細

このコミットが対処している技術的な問題は、net/rpcCodec 実装における並行アクセス時の安全性です。

net/rpc のクライアントは、複数のゴルーチンから同時にRPC呼び出しを行うことができます。同様に、サーバーは複数のクライアントからのリクエストを並行して処理できます。これらのシナリオでは、ClientCodecWriteRequest メソッドや ServerCodecWriteResponse メソッドが、異なるゴルーチンから同時に呼び出される可能性があります。

例えば、ClientCodec.WriteRequest は、RPCリクエストをネットワーク接続に書き込む役割を担います。もし複数のゴルーチンが同時に WriteRequest を呼び出した場合、ネットワーク接続への書き込みがインターリーブされ、破損したリクエストが送信される可能性があります。これは、ネットワーク接続が共有リソースであり、一度に一つの書き込み操作のみが許可されるべきであるためです。

同様に、ServerCodec.WriteResponse も、サーバーの応答をネットワーク接続に書き込むため、並行アクセスに対して保護される必要があります。

このコミット以前は、Codec インターフェースのドキュメントには、これらのメソッドが並行アクセスに対して安全であるべきかどうかの明示的な指示がありませんでした。これにより、カスタム Codec を実装する開発者は、これらのメソッドが自動的にスレッドセーフであると誤解したり、スレッドセーフティを考慮せずに実装してしまい、並行環境で予期せぬバグ(データ破損、デッドロックなど)を引き起こす可能性がありました。

このコミットは、WriteRequestWriteResponse メソッドに「// WriteRequest must be safe for concurrent use by multiple goroutines.」というコメントを追加することで、この要件を明確にしています。これは、Codec の実装者が、これらのメソッド内で共有リソースへのアクセスを適切に同期させる責任があることを示しています。通常、これはミューテックスを使用して、書き込み操作を排他的に実行することで実現されます。

このドキュメントの追加は、net/rpc パッケージの堅牢性と信頼性を向上させ、開発者がより安全で正しいRPCアプリケーションを構築するのに役立ちます。

コアとなるコードの変更箇所

このコミットによるコードの変更は非常にシンプルで、既存のインターフェース定義にコメントを追加するだけです。

diff --git a/src/pkg/net/rpc/client.go b/src/pkg/net/rpc/client.go
index 4b0c9c3bba..608894fb0d 100644
--- a/src/pkg/net/rpc/client.go
+++ b/src/pkg/net/rpc/client.go
@@ -58,6 +58,7 @@ type Client struct {
 // argument to force the body of the response to be read and then
 // discarded.
 type ClientCodec interface {
+// WriteRequest must be safe for concurrent use by multiple goroutines.
 	WriteRequest(*Request, interface{}) error
 	ReadResponseHeader(*Response) error
 	ReadResponseBody(interface{}) error
diff --git a/src/pkg/net/rpc/server.go b/src/pkg/net/rpc/server.go
index fe1cdde1ad..9ccd703b12 100644
--- a/src/pkg/net/rpc/server.go
+++ b/src/pkg/net/rpc/server.go
@@ -616,6 +616,7 @@ func RegisterName(name string, rcvr interface{}) error {
 type ServerCodec interface {
 	ReadRequestHeader(*Request) error
 	ReadRequestBody(interface{}) error
+// WriteResponse must be safe for concurrent use by multiple goroutines.
 	WriteResponse(*Response, interface{}) error
 
 	Close() error

コアとなるコードの解説

追加されたコメントは以下の通りです。

  1. src/pkg/net/rpc/client.goClientCodec インターフェース内:

    type ClientCodec interface {
    	// WriteRequest must be safe for concurrent use by multiple goroutines.
    	WriteRequest(*Request, interface{}) error
    	// ...
    }
    

    このコメントは、ClientCodecWriteRequest メソッドが、複数のゴルーチンから同時に呼び出されても安全に動作しなければならないことを明示しています。これは、Client が複数のRPC呼び出しを並行して行う可能性があるため、WriteRequest の実装は内部的に同期メカニズム(例: sync.Mutex)を使用して、共有リソース(通常は基になるネットワーク接続)へのアクセスを保護する必要があることを意味します。

  2. src/pkg/net/rpc/server.goServerCodec インターフェース内:

    type ServerCodec interface {
    	// ...
    	// WriteResponse must be safe for concurrent use by multiple goroutines.
    	WriteResponse(*Response, interface{}) error
    	// ...
    }
    

    同様に、このコメントは ServerCodecWriteResponse メソッドが、複数のゴルーチンから同時に呼び出されても安全に動作しなければならないことを示しています。サーバーは複数のクライアントからのリクエストを並行して処理し、それぞれに応答を書き込む可能性があるため、WriteResponse の実装も共有リソースへのアクセスを適切に同期させる必要があります。

これらのコメントは、コードの動作を変更するものではなく、net/rpc パッケージのユーザー(特にカスタム Codec を実装する開発者)に対する重要なドキュメントの追加です。これにより、Codec の実装におけるスレッドセーフティの要件が明確になり、並行処理における潜在的なバグを防ぐのに役立ちます。

関連リンク

参考にした情報源リンク