以å Perl ã§ãforkãã¦ä¸¦åå®è¡ãããã³ããã¼ã¯ãåãããã®ã©ã¤ãã©ãªãParallel::Benchmark ã¨ããã®ãæ¸ãã¾ããã
ããã使ãã¨ãåã« Perl ã³ã¼ãã®ãã³ããã¼ã¯ã ãã§ã¯ãªãã並åã«å¤é¨ã«ã¢ã¯ã»ã¹ãã¦è¨æ¸¬ãè¡ããã㪠(ãã¨ãã°ApacheBenchã®ãããª) ãã³ããã¼ã¯ãã¼ã«ãç°¡åã«ä½ããã®ã§éå®ãã¦ãã¾ãã(ä»äºã§ã¯ãã½ã¼ã·ã£ã«ã²ã¼ã ã®ãµã¼ãã¢ããªã±ã¼ã·ã§ã³ã«å¯¾ããè² è·ãã¹ããè¡ãããã«ä½¿ã£ããããã¦ãã¾ã)
ã§ãæãç«ã£ã¦ Go çãæ¸ãã¾ããã
使ç¨ä¾
ãã£ããããæ°ãæ±ããã³ã¼ãã並åå®è¡ãããã³ããã¼ã¯
- fib(30) ã1åè¨ç®ãããã¨ã«ã¹ã³ã¢1ã¨ãã
- 10åã® goroutine ã§ä¸¦åå®è¡
- 3ç§éè¨æ¸¬
package main import ( "github.com/kayac/parallel-benchmark/benchmark" "log" "time" ) func main() { result := benchmark.RunFunc( func() (subscore int) { fib(30) return 1 }, time.Duration(3)*time.Second, 10, ) log.Printf("%#v", result) } func fib(n int) int { if n == 0 { return 0 } if n == 1 { return 1 } return (fib(n-1) + fib(n-2)) }
å®è¡çµæã¯ãããªæãã§ãã
$ go run fib.go 2014/07/18 14:24:52 starting benchmark: concurrency: 10, time: 3s, GOMAXPROCS: 1 2014/07/18 14:24:55 done benchmark: score 330, elapsed 3.303671587s = 99.888863 / sec 2014/07/18 14:24:55 &benchmark.Result{Score:330, Elapsed:3303671587}
ä½¿ãæ¹ã¯ç°¡åã§ãbenchmark.RunFunc() ã«è¨æ¸¬ãããå¦çã® func() int ãæ¸¡ãã ãã§ãã
渡ãã func ãè¿ãã int å¤ã1åå®è¡ãã¨ã®ã¹ã³ã¢ã«ãªãã®ã§ãå¦çå
容ã«ãã£ã¦éãã¹ã³ã¢ãè¿ããã¨ãã§ãã¾ãã(失æããã 0 ã¨ã)
GOMAXPROCS ã¯é©å®ç°å¢å¤æ°ã§æ¸¡ããªã©ãã¦ãã ããã
$ GOMAXPROCS=4 go run fib.go 2014/07/18 14:28:56 starting benchmark: concurrency: 10, time: 3s, GOMAXPROCS: 4 2014/07/18 14:28:59 done benchmark: score 974, elapsed 3.097321734s = 314.465233 / sec 2014/07/18 14:28:59 &benchmark.Result{Score:974, Elapsed:3097321734}
ApacheBench ã®ãã㪠HTTP GET ãè¡ããã³ããã¼ã¯
benchmark.Worker interface ãå®è£ ãããèªåã® Worker ãªãã¸ã§ã¯ããã¹ã©ã¤ã¹ã§æ¸¡ããã¨ã§ãç¶æ ãæã£ããªãã¸ã§ã¯ãã使ã£ããã³ããã¼ã¯ãä½ããã¨ãã§ãã¾ãã
package main import ( "flag" "github.com/kayac/parallel-benchmark/benchmark" "io/ioutil" "log" "net/http" "time" ) type myWorker struct { URL string client *http.Client } func (w *myWorker) Setup() { w.client = &http.Client{} } func (w *myWorker) Teardown() { } func (w *myWorker) Process() (subscore int) { resp, err := w.client.Get(w.URL) if err == nil { defer resp.Body.Close() _, _ = ioutil.ReadAll(resp.Body) if resp.StatusCode == 200 { return 1 } } else { log.Printf("err: %v, resp: %#v", err, resp) } return 0 } func main() { var ( conn int duration int ) flag.IntVar(&conn, "c", 1, "connections to keep open") flag.IntVar(&duration, "d", 1, "duration of benchmark") flag.Parse() url := flag.Args()[0] // benchmark.Worker interface ããã£ã worker ã使ãã¦ã¹ã©ã¤ã¹ã«å ¥ãã workers := make([]benchmark.Worker, conn) for i, _ := range workers { workers[i] = &myWorker{URL: url} } benchmark.Run(workers, time.Duration(duration)*time.Second) }
- Setup() : goroutine ã使ãããå¾ãåworkerã§å¼ã°ãã¾ããåæåãè¡ãã®ã«å©ç¨ãã¦ãã ãã
- Process() int: å ¨ã¦ã® worker ã® Setup() ãçµäºå¾ãå worker ã® Process() ãæå®æéã«éããã¾ã§ã«ã¼ãã§å¼ã³åºããã¾ããè¿ã int å¤ã1åå®è¡ãã¨ã®ã¹ã³ã¢ã«ãªãã¾ã
- Teardown(): æå®æéãçµéå¾ãå worker ã§å¼ã°ãã¾ããå¾å¦çãå¿ è¦ã§ããã°ããã§è¡ã£ã¦ãã ãã
å®è£ ä¸ã®ãã¤ã³ãã¨ã
Perlçã§ãåæ§ãªã®ã§ããããã³ããã¼ã¯ãåãã¨ãã«ã¡ãã£ã¨å¬ããå°ãã¿ãå ¥ã£ã¦ãã¾ãã
- ãã¹ã¦ã® worker ã®åæåãçµããã®ãå¾ ã£ã¦ããè¨æ¸¬éå§ããã®ã§ãéãåæåå¦çããã£ã¦ãéå§ãæã
- éä¸ã§ã·ã°ãã« (INT, TERM, QUIT, HUP) ãåããå ´åã¯ãããã§è¨æ¸¬ãçµäºãã¦ãã®æç¹ã§ã®çµæãè¿ã
- ã¤ãè¨æ¸¬æé10åã§ãã³ãå§ãããã©å¾ ã¤ã®è¾ãã®ã§5åã«ãããããã©ä¸æãããããã¾ã§ã®è¨æ¸¬ãç¡é§ã«â¦ã¨ãããããªã±ã¼ã¹ã§ãèºèºãªã忢ã§ãã¾ã
Perlçã§ã¯ä¸è¨ã®æåãå®è£ ããããã« fork ããåããã»ã¹ãåæåå®äºããã®ã Parallel::Scoreborad ã§å¾ ã£ãããåããã»ã¹ãå¶å¾¡ããã®ã«ã·ã°ãã«ãéã£ãããã¦ãã¦ãªããªãè¤éãªå®è£ ã«ãªã£ã¦ããã®ã§ãããGoã§ã¯ channel ã使ããã®ã§å¤§å¤æ¥½ã«æ¸ãã¦ãã°ãããã§ããã