6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Goで並行処理のベンチマークをとる

Last updated at Posted at 2016-03-24

概要

Goの高速なHTTPサーバ、クライアントパッケージであるfasthttpについて調査していました。ザーッとfasthttpのコードを追っていて、ベンチマークの処理が気になったので中身を見てみると、タイトルのような目的でベンチマークを取っていました。
あまり日本語の情報がなかったので、メモを残しておきます。

ちなみにGoのバージョンは1.6です。

コード例

実際にfasthttpのベンチマークのコードを見るとわかるかもしれませんが、
簡単な例を残しておきます。

http_test.go
package hoge

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"testing"
)

func benchmarkWithParallel(b *testing.B, parallelism int) {
	addr := "127.0.0.1:9999"

	ln, err := net.Listen("tcp4", addr)
	if err != nil {
		b.Fatalf("cannot listen %q: %s", addr, err)
	}

	handler := func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "hello, world")
	}

	ch := make(chan struct{})
	go func() {
		if err := http.Serve(ln, http.HandlerFunc(handler)); err != nil && !strings.Contains(
			err.Error(), "use of closed network connection") {
			b.Fatalf("http.Serve() error: %s", err)
		}
		close(ch)
	}()

	c := &http.Client{
		Transport: &http.Transport{
			MaxIdleConnsPerHost: parallelism,
		},
	}

	URL := "http://" + addr + "/hello"
	b.SetParallelism(parallelism)
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			resp, err := c.Get(URL)
			if err != nil {
				b.Fatalf("http.Get() error: %v", err)
			}
			_, _ = ioutil.ReadAll(resp.Body)
			resp.Body.Close()
		}
	})

	ln.Close()
	<-ch
}

func BenchmarkNilContinueWithParallel1(b *testing.B) {
	benchmarkWithParallel(b, 1)
}

func BenchmarkNilContinueWithParallel2(b *testing.B) {
	benchmarkWithParallel(b, 2)
}

func BenchmarkNilContinueWithParallel10(b *testing.B) {
	benchmarkWithParallel(b, 10)
}

func BenchmarkNilContinueWithParallel20(b *testing.B) {
	benchmarkWithParallel(b, 20)
}

実行結果

$ go test -bench Parallel -benchmem -cpu=1,2,4 -benchtime=2s
testing: warning: no tests to run
PASS
BenchmarkNilContinueWithParallel1   	   50000	     65503 ns/op	    4236 B/op	      49 allocs/op
BenchmarkNilContinueWithParallel1-2 	   30000	    152424 ns/op	    5587 B/op	      54 allocs/op
BenchmarkNilContinueWithParallel1-4 	    5000	    844317 ns/op	    9953 B/op	      70 allocs/op
BenchmarkNilContinueWithParallel2   	   50000	     53632 ns/op	    4236 B/op	      49 allocs/op
BenchmarkNilContinueWithParallel2-2 	   50000	     48256 ns/op	    4260 B/op	      49 allocs/op
BenchmarkNilContinueWithParallel2-4 	   10000	    564127 ns/op	    6446 B/op	      57 allocs/op
BenchmarkNilContinueWithParallel10  	   50000	     58109 ns/op	    4231 B/op	      48 allocs/op
BenchmarkNilContinueWithParallel10-2	   50000	     47181 ns/op	    4242 B/op	      48 allocs/op
BenchmarkNilContinueWithParallel10-4	  100000	     34683 ns/op	    4247 B/op	      48 allocs/op
BenchmarkNilContinueWithParallel20  	    3000	    943406 ns/op	    4364 B/op	      48 allocs/op
BenchmarkNilContinueWithParallel20-2	   50000	     60116 ns/op	    4243 B/op	      48 allocs/op
BenchmarkNilContinueWithParallel20-4	  100000	     33019 ns/op	    4245 B/op	      48 allocs/op
ok  	_/tmp_golang/bbb	49.072s

RunParallelとSetParallelism

パッケージドキュメントRunParallelの動作について説明があります。

RunParallelは並行処理のベンチマークを実施する。複数のgoroutinesを作成し、b.Nの中で分散実行する。
goroutinesの数はデフォルトでGOMAXPROCSになっている。CPUバウンドではないベンチマークの場合、
RunParallelを呼ぶ前にSetParallelismを呼んで並行数を増やす。

body関数は1goroutine毎に実行される。goroutineローカルな処理を書き、pb.Nextがfalseを返すまで実行するべき。
StartTimer、StopTimer、ResetTimer関数を内部で使うべきではない。なぜなら、それらはグローバルな影響を与えるため。

さらにSetParallelismの項にも説明があります。

SetParallelism(p int)はRunParallelで使うgoroutinesの数をp*GOMAXPROCSに設定する。
CPUバウンドなベンチマークでは通常SetParallelismを呼ぶ必要はない。
もしpが1未満の場合、この呼び出しはなにも効果がない。

その他

知ってる人は知ってそうなTipsっぽいですが、知らなかったのでメモ。

  • テストの中で何か出力して確認したい場合はtesting.T.Logとかtesting.B.Logを使う。
  • テスト用にHTTPサーバを使いたい場合はnet/http/httptesthttptest.NewServerというまさにそれなのがすでにある。

いじょ

6
6
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
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?