通过实例入门Golang

栏目: Go · 发布时间: 7年前

内容简介:通过实例入门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 常见的用法,搞懂它基本就算入门了。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

智能

智能

[法]弗雷德里克·马特尔 / 君瑞图、左玉冰 / 商务印书馆 / 2015-8 / 59.90

揭示数字化主流大趋势的最新权威论著 《主流》作者的最新力作!与法国秋季新版同步上市! 面对数字化时代的到来,美国、欧盟、中国、俄罗斯、印度、巴西、古巴、伊朗、南非、韩国、新加坡、肯尼亚、墨西哥、日本等世界各国各地区正在如何应对? 在国际地缘政治格局下如何把握数字化主流的大趋势? 谷歌、苹果、脸书、亚马逊、阿里巴巴、腾讯、中兴、华为等大家熟知的网络巨头接受了作者的采访。作者的......一起来看看 《智能》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具