后端程序员为什么选择go?

后端程序员为什么选择go?

  • 语法简单,入门快
  • 编译型语言,性能高,语言原生支持并发对后端程序员很有吸引力
  • 开发效率高,对于写api的后端程序员来说,golang的开发效率非常接近python,php等脚本语言
  • 社区活跃,大牛项目多,高质量的代码都可以任意阅读 (etcd,docker,k8s)

先看一个demo

package main
import (
    "io"
    "net/http"
)
func helloHandler(w http.ResponseWriter, req *http.Request) {
    io.WriteString(w, "hello, world!\n")
}

func main() {
    http.HandleFunc("/", helloHandler)
    http.ListenAndServe(":8888", nil)
}
$ go run main.go

这个demo程序实现一个weh服务,浏览器(或者curl)访问 http://localhost:8888/ 会显hello, world

现在来用ab工具来做下基准测试,100个client请求1w次的结果(环境 deepin golang 1.12.1 no nginx)。

$ ab -n 10000 -c 100 http://localhost:8888/

结果

Concurrency Level:      100
Time taken for tests:   0.425 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      1310000 bytes
HTML transferred:       140000 bytes
Requests per second:    23556.40 [#/sec] (mean)
Time per request:       4.245 [ms] (mean)
Time per request:       0.042 [ms] (mean, across all concurrent requests)
Transfer rate:          3013.56 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   0.4      2       4
Processing:     1    2   0.6      2       6
Waiting:        0    2   0.6      2       5
Total:          2    4   0.5      4       8

Percentage of the requests served within a certain time (ms)
  50%      4
  66%      4
  75%      4
  80%      4
  90%      5
  95%      5
  98%      6
  99%      6
 100%      8 (longest request)

现在用php7.2试一下同样的程序效果,比一下(环境 deepin linux nginx1.13.12 100 static php7.2-fpm)

$ ab -n 10000 -c 100 http://localhost/index.php

代码

index.php

<?php

echo "hello world";

结果

Concurrency Level:      100
Time taken for tests:   0.702 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      1490000 bytes
HTML transferred:       110000 bytes
Requests per second:    14237.51 [#/sec] (mean)
Time per request:       7.024 [ms] (mean)
Time per request:       0.070 [ms] (mean, across all concurrent requests)
Transfer rate:          2071.67 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.6      1       4
Processing:     1    4   3.6      3     192
Waiting:        1    4   3.5      3     174
Total:          1    5   3.5      4     192

Percentage of the requests served within a certain time (ms)
  50%      4
  66%      5
  75%      6
  80%      6
  90%      8
  95%      9
  98%     12
  99%     21
 100%    192 (longest reques)

对比结果golang在简单的hello world 程序下qps大概是php7.2的2倍。需要注意的是golang的web程序编译完之后就一个可执行文件,不依赖第三方库,这个可执行文件可以在任意linux系统上运行,不需要而外配置环境变量,这个和c和c++编译完的程序运行方式不太一样。c和c++即使是完全静态编译后,还需要看libc版本是不是和编译时的是否兼容,golang的这种特性,在容器化和微服务化的项目中非常占优。php的程序按照目前的主流架构,是需要nginx和php-fpm两个程序配合,同时把代码部署到站点目录。

改进demo程序 实现全局计数器

package main
import (
	"fmt"
	"io"
	"net/http"
	"sync/atomic"
)
var counter int32 = 0
func helloHandler(w http.ResponseWriter, req *http.Request) {
	atomic.AddInt32(&counter, 1)
	io.WriteString(w, "hello, world!")

}
func getCounter(w http.ResponseWriter, req *http.Request) {
	atomic.AddInt32(&counter, 1)
	io.WriteString(w, fmt.Sprintf("count : %d", atomic.LoadInt32(&counter)))
}
func main() {
	http.HandleFunc("/", helloHandler)
	http.HandleFunc("/count", getCounter)
	http.ListenAndServe(":8888", nil)
}

两个接口 http://localhost:8888/count 和 http://localhost:8888/ 都会对全局counter 原子性加1,注意golang 的http Handle fution 是运行在golang goroutine(协程)里头,goroutine 是并发运行的,所以对全局的counter修改会有data race(数据竞争),需要加锁或者使用原子操作,这边使用golang的原子操作包实现

$ curl http://localhost:8888/count        count : 1
$ curl http://localhost:8888/count        hello, world  //count : 2
$ curl http://localhost:8888/count        count : 3

后续的课程章节会学习到golang的http server是如何运行的。

总结

本节课用一个简单的golang web demo实现了hello world程序,同时实现了一个简单的全局计数器。golang官方包支持http server,对于一些简单的api项目用官方包实现起来十分便捷。