解答 03.4 — RPC(Multiply)¶
このノートブックは 03.4-rpc.ipynb の練習問題の解答です。
まず問題の前提コードを再掲し、次に解答、最後にチェックを実行します。
先に自分の力で解いてから、答え合わせに使ってください。
前提コード(問題ノートブックと同じ定義)¶
In [1]:
import (
"errors"
"fmt"
"net"
"net/rpc"
"time"
)
// ErrUnanswered は、練習問題が未回答のときにプレースホルダ関数が返す特別なエラー。
var ErrUnanswered = errors.New("未回答: この関数はまだ実装されていません")
type MathService struct{}
type AddArgs struct {
A, B float64
}
func (m *MathService) Add(args AddArgs, reply *float64) error {
*reply = args.A + args.B
return nil
}
// newPipeRPC は net.Pipe() 越しに MathService を公開したサーバーと、
// それに繋がったクライアントを1組作る。呼び出し側は必ず client.Close() → <-done(有限待機)まで行うこと。
func newPipeRPC() (client *rpc.Client, done chan struct{}) {
server := rpc.NewServer()
if err := server.Register(new(MathService)); err != nil {
panic(err)
}
clientConn, serverConn := net.Pipe()
done = make(chan struct{})
go func() {
defer close(done)
server.ServeConn(serverConn)
}()
client = rpc.NewClient(clientConn)
return client, done
}
func waitDone(done chan struct{}) {
select {
case <-done:
case <-time.After(2 * time.Second):
fmt.Println("⚠️ サーバーgoroutineがタイムアウトした(client.Close()が呼ばれたか確認してください)")
}
}
解答: Multiply¶
Add と同じ形(func (m *MathService) M(args AddArgs, reply *float64) error)で、
*reply に積をセットするだけです。
In [2]:
func (m *MathService) Multiply(args AddArgs, reply *float64) error {
*reply = args.A * args.B
return nil
}
チェック(問題ノートブックと同じ期待値)¶
答え合わせ用のヘルパー mustEqual を定義します。
In [3]:
import "reflect"
func mustEqual(got, want any, name string) {
if reflect.DeepEqual(got, want) {
fmt.Printf("✅ Passed: %s\n", name)
return
}
panic(fmt.Sprintf("❌ %s\n got = %v (%T)\n want = %v (%T)", name, got, got, want, want))
}
In [4]:
%%
client, done := newPipeRPC()
var product float64
mulErr := client.Call("MathService.Multiply", AddArgs{A: 6, B: 7}, &product)
client.Close()
waitDone(done)
mustEqual(mulErr, nil, "Multiply はエラーなし")
mustEqual(product, float64(42), "Multiply(6, 7) = 42")
fmt.Println("🎉 すべてのチェックが通りました")
✅ Passed: Multiply はエラーなし ✅ Passed: Multiply(6, 7) = 42 🎉 すべてのチェックが通りました
解説¶
Addと同じ形:net/rpcのメソッドはfunc (t *T) M(args T1, reply *T2) errorという決まった 形さえ守れば、既存メソッドをコピーしてロジックだけ変えるだけで新しいRPCメソッドを追加できます- 登録は自動:
server.Register(new(MathService))はMathServiceの全てのエクスポートされた メソッドをまとめて登録するため、Multiplyを追加しても再登録のコードは不要です(同じnewPipeRPCのままで新しいメソッドが呼べるようになります)