※注意: この記事ははあくまで個人学習用に整理しただけの記事で、内容としては不完全なものになります。読んでも参考にならない可能性が高いです。
golang を勉強し始めてたが、ServeMux がいまいちわからないのでまとめる
ServeMux とは
公式ドキュメントには以下のように書いてある
https://golang.org/pkg/net/http/#ServeMux
ServeMux is an HTTP request multiplexer. It matches the URL of each incoming request against a list of registered patterns and calls the handler for the pattern that most closely matches the URL.
ServeMuxはHTTPリクエストマルチプレクサーです。各着信リクエストのURLを登録済みパターンのリストと照合し、URLに最も近いパターンのハンドラーを呼び出します。
マルチプレクサー というのは。。。?
マルチプレクサ、多重器、多重装置、多重化装置、合波器(multiplexer)は、ふたつ以上の入力をひとつの信号として出力する機構である。通信分野では多重通信の入口の装置、電気・電子回路では複数の電気信号をひとつの信号にする回路である。しばしばMUX等と略される。
複数の信号を入力として受け取り、1つの信号にして出力するもののようだ。http リクエストのマルチプレクサーが ServeMux ということらしい。routing を実現するための構造体のようだ。
ServeMux は以下のような構造になっている。
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
sync.RWMutex ? muxEntry ? また未知のものが出てきた。。
sync.RWMutex とは
A RWMutex is a reader/writer mutual exclusion lock. The lock can be held by an arbitrary number of readers or a single writer. The zero value for a RWMutex is an unlocked mutex.
RWMutexは、リーダー/ライターの相互排他ロックです。ロックは、任意の数のリーダーまたは単一のライターが保持できます。 RWMutexのゼロ値は、ロックされていないミューテックスです。
正確には理解できていないが、リーダー/ライターの相互排他ロックとのこと。
以下のような構造になっている。
https://golang.org/src/sync/rwmutex.go?s=987:1319#L18
type RWMutex struct {
w Mutex // held if there are pending writers
writerSem uint32 // semaphore for writers to wait for completing readers
readerSem uint32 // semaphore for readers to wait for completing writers
readerCount int32 // number of pending readers
readerWait int32 // number of departing readers
}
また Mutex というわからないものが出てきた。
sync.Mutex とは
A Mutex is a mutual exclusion lock.
The zero value for a Mutex is an unlocked mutex.
Mutexは相互排他ロックです。
ミューテックスのゼロ値はロックされていないミューテックスです。
ロックについては以下の記事がわかりやすかった
Go でロックする
sync.Mutex【Go】
A Tour of Go
複数の goroutines から並行処理で、同じ変数を変更したりする際にロックが重要になるとのこと。
RWMutex はそのリーダー/ライター版ってことかな?
そして muxEntry についても確認
http.muxEntry とは
http パッケージ内に以下のように定義されている
type muxEntry struct {
h Handler
pattern string
}
Handler と URL パターンを持った構造体だ。
muxEntry は、以下の ServeMux の Handle method で使用されている。
https://golang.org/src/net/http/server.go?h=muxEntry#L2420
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}
if mux.m == nil {
mux.m = make(map[string]muxEntry) // フィールド m にmake(map[string]muxEntry) が代入され
}
// muxEntry 構造体を h handler, pattern pattern で初期化した e 変数を作成
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e // mux.m[pattern]に代入されている。
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}
if pattern[0] != '/' {
mux.hosts = true // パターンにホスト名が含まれているかどうか
}
}
func appendSorted(es []muxEntry, e muxEntry) []muxEntry {
n := len(es)
i := sort.Search(n, func(i int) bool {
return len(es[i].pattern) < len(e.pattern)
})
if i == n {
return append(es, e)
}
// we now know that i points at where we want to insert
es = append(es, muxEntry{}) // try to grow the slice in place, any entry works.
copy(es[i+1:], es[i:]) // Move shorter entries down
es[i] = e
return es
}
mux.esは
slice of entries sorted from longest to shortest.
最長から最短にソートされたエントリのスライス。
とのこと。appendSorted でソートしたエントリのスライスを生成して、mux.esへ格納している
なぜ ServeMux の Handle メソッドを実装した際に sync.RWMutex で lock する必要があるのかは読み解けなかった。。。
まとめると、
ServeMux は
- reader / writer ロックの為の sync.RWMutex
- URL と Hander の map
- sort した URL の配列
- パターンにホスト名が含まれているかどうかのフラグ
以上を保有した構造体だった。
あんまりわかってないけど、一旦そういうものと整理しておく。