LoginSignup
17
14

More than 5 years have passed since last update.

Goのclosureへのパラメータの渡し方

Posted at

Effective Go#channelsに載ってるclosureへのパラメータの渡し方2パターンのperformanceを比較した。

きっかけ

  • Go研vol.16で、ほぼ同じだけどclosureへのパラメータの渡し方だけ違うコードがあった。

  • 2つの書き方でperformanceに差があるのか調べてみよう。

closureへのパラメータの渡し方

以下はEffective Goからの引用。

Effective Go#channels

loop変数はloop内で繰り返し再利用されるため、下記コードはバグがある。
全てのgoroutineでloop変数を共有した状態になってしまう。

bug.go
func Serve(queue chan *Request) {
    for req := range queue {
        sem <- 1
        go func() {
            process(req)
            <- sem
        }()
    }
}

解決策として、Effective Goでは以下2パターンを上げている。

1.closureに引数として渡す

pattern1.go
func Serve(queue chan *Request) {
    for req := range queue {
        sem <- 1
        go func(req *Request) {
            process(req)
            <-sem
        }(req)
    }
}

2.loop中でloop変数と同じ名前の変数を作る

pattern2.go
func Serve(queue chan *Request) {
    for req := range queue {
        req := req // Create new instance of req for the goroutine.
        sem <- 1
        go func() {
            process(req)
            <-sem
        }()
    }
}

performance比較

上記2パターンのperformanceをgo test -benchで比較した。
ソースコード

results
BenchmarkClosure1        500       5356625 ns/op       11165 B/op         38 allocs/op
BenchmarkClosure2        500       6917004 ns/op      262473 B/op      20029 allocs/op

結果

  • pattern2はpattern1と比較して、より多くのメモリを確保する
  • ちゃんとclosureに引数として渡すように書いたほうが良い
17
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
14