内容简介:通过实例入门Golang
如果想学会一门新语言,不仅要多读文档,还要多看别人写的代码,更要强迫自己用新语言多写代码。我在学习 Golang 之前,读过好几本相关的书籍,不过总感觉没真正学会,于是我决定动手用 Golang 写一个能用的 工具 试试,因为 Golang 最大的优势就是 goroutine 和 channel,所以我觉得实现一个简版的 ab(Web 压力测试工具)应该是一个不错的选择,用 Golang 磕磕绊绊总算实现了预想的功能,能够计算 Requests per second 和 Time per request 的值,不过总感觉写出来的代码不够漂亮,于是我又找来 hey 的代码前后读了几遍,然后结合自己的理解临摹了一遍,感觉总算是入门了。
虽然 hey 的代码本身已经相当简洁,但是洋洋洒洒加起来也有五六百行代码,下面是我默写的版本,仅保留主体功能,总共就一两百行代码:
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"strings"
"sync"
"time"
)
var usage = `Usage: %s [options]
Options are:
-n requests Number of requests to perform
-c concurrency Number of multiple requests to make at a time
-s timeout Seconds to max. wait for each response
-m method Method name
`
var (
requests int
concurrency int
timeout int
method string
url string
)
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, usage, os.Args[0])
}
flag.IntVar(&requests, "n", 1000, "")
flag.IntVar(&concurrency, "c", 100, "")
flag.IntVar(&timeout, "s", 10, "")
flag.StringVar(&method, "m", "GET", "")
flag.Parse()
if flag.NArg() != 1 {
exit("Invalid url.")
}
method = strings.ToUpper(method)
url = flag.Args()[0]
if method != "GET" {
exit("Invalid method.")
}
if requests < 1 || concurrency < 1 {
exit("-n and -c cannot be smaller than 1.")
}
if requests < concurrency {
exit("-n cannot be less than -c.")
}
w := Work{
Requests: requests,
Concurrency: concurrency,
Timeout: timeout,
Method: method,
Url: url,
}
w.Run()
}
func exit(msg string) {
flag.Usage()
fmt.Fprintln(os.Stderr, "\n[Error] "+msg)
os.Exit(1)
}
type Work struct {
Requests int
Concurrency int
Timeout int
Method string
Url string
results chan *Result
start time.Time
end time.Time
}
type Result struct {
Duration time.Duration
}
func (w *Work) Run() {
w.results = make(chan *Result, w.Requests)
w.start = time.Now()
w.runWorkers()
w.end = time.Now()
close(w.results)
w.print()
}
func (w *Work) runWorkers() {
var wg sync.WaitGroup
wg.Add(w.Concurrency)
for i := 0; i < w.Concurrency; i++ {
go func() {
w.runWorker(w.Requests / w.Concurrency)
defer wg.Done()
}()
}
wg.Wait()
}
func (w *Work) runWorker(num int) {
client := &http.Client{
Timeout: time.Duration(w.Timeout) * time.Second,
}
for i := 0; i < num; i++ {
w.sendRequest(client)
}
}
func (w *Work) sendRequest(client *http.Client) {
req, err := http.NewRequest(w.Method, w.Url, nil)
if err != nil {
log.Fatal(err.Error())
}
start := time.Now()
client.Do(req)
end := time.Now()
w.results <- &Result{
Duration: end.Sub(start),
}
}
func (w *Work) print() {
sum := 0.0
num := float64(len(w.results))
for result := range w.results {
sum += result.Duration.Seconds()
}
rps := int(num / w.end.Sub(w.start).Seconds())
tpr := sum / num * 1000
fmt.Printf("Requests per second:\t%d [#/sec]\n", rps)
fmt.Printf("Time per request:\t%.3f [ms]\n", tpr)
}
代码虽短,却涵盖了 Golang 常见的用法,搞懂它基本就算入门了。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 超级简单入门vuex 小实例
- 实例入门 Vue.js 单元测试
- 实例详解Spring MVC入门使用
- Spark 入门实战之最好的实例
- electron vue桌面应用入门实例
- 机器学习入门教程:启发式实例
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。