package main
import (
"context"
"flag"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"sync"
"time"
)
var concurrency int // -c
var timeout int // -t
var requests int // -n
var version string // -V
var url string // -l
var method string // -X
var data string // -d
func init() {
flag.IntVar(&concurrency, "c", 5, "concurrency per second")
flag.IntVar(&timeout, "t", 5, "timeout")
flag.IntVar(&requests, "n", 10, "total requests")
flag.StringVar(&version, "V", "1.0.0", "version")
flag.StringVar(&url, "l", "", "must specify a url")
flag.StringVar(&method, "X", "GET", "http method")
flag.StringVar(&data, "d", "", "specify post or put body data")
}
func parseFlag() {
flag.Parse()
if len(os.Args) < 2 || url == "" {
flag.Usage()
os.Exit(0)
}
if concurrency < 0 {
concurrency = 1
} else if (concurrency > requests) {
concurrency = requests
}
url = fixUrl(url)
}
func fixUrl(url string) string {
if strings.Contains(url, "http") {
return url
}
return "http://" + url
}
func handleHttpRequest(url string, pwg *sync.WaitGroup, tch chan<- int64, ctx context.Context, ctlch <-chan int64) {
for {
select {
case <-ctlch:
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
pwg.Done()
continue;
}
resp.Body.Close()
pwg.Done()
_, err = ioutil.ReadAll(resp.Body)
tch <- time.Now().UnixNano() / 1e6
case <-ctx.Done():
break;
}
}
}
func caculate(start int64, ends <-chan int64, total int) {
l := len(ends)
timeUse := make([]int64, 0, l)
var totalUse int64 = 0;
for i := 0; i < l; i++ {
x := <- ends
timeUse = append(timeUse, x - start)
totalUse += (x - start)
}
fmt.Printf("total %d request use time %d ms, success %d, fail %d\r\n", total, totalUse, l, total - l)
fmt.Printf("max cost %d ms\r\n", timeUse[l - 1])
fmt.Printf("min cost %d ms\r\n", timeUse[0])
fmt.Printf("95%% point cost %d ms\r\n", timeUse[int(l * 19 / 20)])
fmt.Printf("avg cost %d ms\r\n", totalUse / int64(l))
}
func main() {
parseFlag()
wg := sync.WaitGroup{}
wg.Add(requests);
tmCtx, cancelFunc := context.WithTimeout(context.Background(), time.Duration(5))
defer cancelFunc()
recvCh := make(chan int64, requests)
defer close(recvCh)
ctrlCh := make(chan int64, requests)
defer close(ctrlCh)
for i := 0; i < concurrency; i++ {
go handleHttpRequest(url, &wg, recvCh, tmCtx, ctrlCh)
}
start := time.Now().UnixNano() / 1e6
for i:= 0; i < requests; i++ {
ctrlCh <- int64(i)
}
wg.Wait()
caculate(start, recvCh, requests)
}
评论