希望通过本次分享能使大家对 Go 这门语言有个初步的认识
Go语言是谷歌2009发布的开源编程语言。
Go是一门类似C语言
的编译型
语言,但是它的编译速度非常快。Go语言主要的设计准则是简洁
。这门语言的关键字总共也就二十五
个,比英文字母还少一个。
(js ES6关键字63个,java 53个, python v3.x 35个)
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
Go 语言的一个设计目标是做到简洁,这里介绍一部分语法,来体验一下有多简洁
var variableName string
var variableName string = "golang"
var vname1, vname2, vname3 string
var vname1, vname2, vname3 string = "v1", "v2", "v3"
vname1, vname2, vname3 := "v1", "v2", "v3"
if
if v := 1; v > 0 {
fmt.Println(v)
}
for (Go没有while关键字)
sum := 1
for sum < 1000 {
sum += sum
}
map 遍历
rating := map[string]float32{"C": 5, "Go": 4.5, "Python": 4.5, "C++": 2}
for k, v := range rating {
fmt.Println(k, v)
}
数组遍历
rating := []int32{11, 22, 33}
for i, v := range rating {
fmt.Println(i, v)
}
switch (break呢?)
integer := 6
switch integer {
case 4:
fmt.Println("The integer was <= 4")
fallthrough
case 5:
fmt.Println("The integer was <= 5")
default:
fmt.Println("default case")
}
func m(A, B int) (int, int) {
return A + B, A * B
}
func main() {
v1, v2 := m(2, 3)
fmt.Println(v1, v2)
}
defer:
func ReadWrite() bool {
file.Open("file")
defer file.Close()
if failureX {
return false
}
if failureY {
return false
}
return true
}
type Human struct {
name string
age int
weight int
}
type Student struct {
Human // 匿名字段,那么默认Student就包含了Human的所有字段
speciality string
}
method
, interface
type Rectangle struct {
width, height float64
}
type Circle struct {
radius float64
}
func (r Rectangle) area() float64 {
return r.width*r.height
}
func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi
}
method 可以继承、重写
type Human struct {
name string
age int
phone string
}
type Student struct {
Human //匿名字段Human
school string
loan float32
}
type Employee struct {
Human //匿名字段Human
company string
money float32
}
// Human对象实现Sayhi方法
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
// Human对象实现Sing方法
func (h *Human) Sing(lyrics string) {
fmt.Println("La la, la la la, la la la la la...", lyrics)
}
// Human对象实现Guzzle方法
func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
// Employee重载Human的Sayhi方法
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //此句可以分成多行
}
//Student实现BorrowMoney方法
func (s *Student) BorrowMoney(amount float32) {
s.loan += amount // (again and again and...)
}
//Employee实现SpendSalary方法
func (e *Employee) SpendSalary(amount float32) {
e.money -= amount // More vodka please!!! Get me through the day!
}
// 定义interface
type Men interface {
SayHi()
Sing(lyrics string)
Guzzle(beerStein string)
}
type YoungChap interface {
SayHi()
Sing(song string)
BorrowMoney(amount float32)
}
type ElderlyGent interface {
SayHi()
Sing(song string)
SpendSalary(amount float32)
}
goroutine
channel
goroutine比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。
goroutine运行在相同的地址空间,因此访问共享内存必须做好同步。那么goroutine之间如何进行数据的通信呢,Go提供了一个很好的通信机制channel。
channel可以与Unix shell 中的双向管道做类比:可以通过它发送或者接收值。
不要通过共享来通信,而要通过通信来共享。
func doSomething() {}
func main() {
go doSomething()
go doSomething()
}
Go 没有公有、私有关键字,通过大小写来实现,大写为公有,小写为私有。 (private, public, export)
main(), init() 函数
import("fmt") import("f fmt") import(". fmt") import("_ fmt")
不允许声明变量但是不使用,否则编译不通过
优点:
- 编译速度快,直接编译成二进制可执行文件
- 静态链接
- 丰富的标准库
- GC
- 内存占用小
- 简化OOP
- 并发能力
- 语法极度简洁,入门门槛低
- 极其严格统一的代码规范
- 固定每半年发布一个小版本, 目前最新的是1.12 Release History
- 谷歌亲儿子
Go = 接近C的运行效率 + 接近Python的开发效率
缺点:
- 异常机制、错误处理
- 依赖管理(版本管理,翻墙下载)
- 没有泛型
- 各种框架、第三方库依然在发展中
社区 VS Google ?
- 云计算
- 容器(docker, k8s, harbor)
- 网络(traefik, seesaw)
- 数据库(prometheus, influxdb, tidb, cockroach)
- 服务端程序
- 分布式(consul, etcd, codis, nsq, seaweedfs, confd)
- 高并发(istio)
- web server
- process
- 大数据 hadoop生态?? (长远可期新的生态)
- 机器学习 (有框架但是不流行)
目前组内已有2个线上Go的微服务在运行
- Go v1.10
- Nodejs v8.11
- Python v3.4
- Java jdk-v1.8
用abtest简单做一下测试, 10w 请求 1k 并发
服务器 centos7 4c 16g
@RestController
public class TestController {
/**
* Output hello world
*/
@RequestMapping(value = "/*", method = RequestMethod.GET)
public ResponseEntity<String> test() {
String outPut = "HelloWorld!";
return new ResponseEntity<>(outPut, HttpStatus.OK);
}
}
10w 请求 1k 并发:
ab -c 1000 -n 100000 http://127.0.0.1:8080/
...
Document Path: /
Document Length: 11 bytes
Concurrency Level: 1000
Time taken for tests: 12.182 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 14400000 bytes
HTML transferred: 1100000 bytes
Requests per second: 8208.81 [#/sec] (mean)
Time per request: 121.820 [ms] (mean)
Time per request: 0.122 [ms] (mean, across all concurrent requests)
Transfer rate: 1154.36 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 87 315.1 2 3023
Processing: 0 27 44.3 16 945
Waiting: 0 25 44.1 14 944
Total: 0 114 322.9 21 3129
Percentage of the requests served within a certain time (ms)
50% 21
66% 28
75% 35
80% 44
90% 145
95% 1021
98% 1044
99% 1114
100% 3129 (longest request)
Nodejs是单线程运行,在该测试中天生吃亏
const http = require("http");
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello there\n');
}).listen(9092)
10w 请求 1k 并发:
ab -c 1000 -n 100000 http://127.0.0.1:9092/
...
Document Path: /
Document Length: 12 bytes
Concurrency Level: 1000
Time taken for tests: 10.652 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 11300000 bytes
HTML transferred: 1200000 bytes
Requests per second: 9388.20 [#/sec] (mean)
Time per request: 106.517 [ms] (mean)
Time per request: 0.107 [ms] (mean, across all concurrent requests)
Transfer rate: 1036.00 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 42 299.6 0 7016
Processing: 12 56 12.6 54 662
Waiting: 0 56 12.6 54 662
Total: 29 98 300.8 54 7068
Percentage of the requests served within a certain time (ms)
50% 54
66% 59
75% 61
80% 62
90% 67
95% 73
98% 1055
99% 1070
100% 7068 (longest request)
package main
import (
"fmt"
"log"
"net/http"
"runtime"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello there!")
}
func main() {
runtime.set
http.HandleFunc("/", hello)
err := http.ListenAndServe(":9099", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
10w 请求 1k 并发:
ab -c 1000 -n 100000 http://127.0.0.1:9099/
...
Document Path: /
Document Length: 12 bytes
Concurrency Level: 1000
Time taken for tests: 5.950 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 12900000 bytes
HTML transferred: 1200000 bytes
Requests per second: 16807.72 [#/sec] (mean)
Time per request: 59.496 [ms] (mean)
Time per request: 0.059 [ms] (mean, across all concurrent requests)
Transfer rate: 2117.38 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 27 5.9 27 45
Processing: 8 32 6.8 32 62
Waiting: 0 23 6.9 23 53
Total: 29 59 6.0 58 92
Percentage of the requests served within a certain time (ms)
50% 58
66% 61
75% 63
80% 64
90% 67
95% 69
98% 73
99% 76
100% 92 (longest request)
Go 只用一个核:
runtime.GOMAXPROCS(1)
ab -c 1000 -n 100000 http://127.0.0.1:9099/
...
Document Path: /
Document Length: 12 bytes
Concurrency Level: 1000
Time taken for tests: 6.420 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 12900000 bytes
HTML transferred: 1200000 bytes
Requests per second: 15577.49 [#/sec] (mean)
Time per request: 64.195 [ms] (mean)
Time per request: 0.064 [ms] (mean, across all concurrent requests)
Transfer rate: 1962.40 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.2 0 32
Processing: 4 63 24.0 75 111
Waiting: 0 63 24.0 75 105
Total: 4 64 23.7 75 111
Percentage of the requests served within a certain time (ms)
50% 75
66% 76
75% 77
80% 78
90% 80
95% 82
98% 84
99% 86
100% 111 (longest request)
#!/usr/bin/env python
from http.server import BaseHTTPRequestHandler, HTTPServer
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
message = "Hello world!"
self.wfile.write(bytes(message, "utf8"))
def log_message(self, format, *args):
return
def run():
print('starting server...')
server_address = ('127.0.0.1', 4477)
httpd = HTTPServer(server_address, testHTTPServer_RequestHandler)
print('running server...')
httpd.serve_forever()
run()
ab -c 1000 -n 100000 http://127.0.0.1:4477/
压测期间server半途直接报错不止。。
以上数据横向对比一下子:
Go | Nodejs | Java | Python | |
---|---|---|---|---|
Total time(s) | 5.950 | 10.652 | 12.182 | 😰 |
Requests per second(#/sec) | 16807 | 9388 | 8208 | 😰 |
Time min(ms) | 29 | 29 | 0 | 😰 |
Time mean(ms) | 59 | 98 | 114 | 😰 |
Time median(ms) | 58 | 54 | 21 | 😰 |
Time max(ms) | 92 | 7068 | 3129 | 😰 |
在不同并发量下测试发现:
- Nodejs: 低并发量,单线程的Nodejs表现优于Go,不愧是纯异步非阻塞,并发量到一定程度,表现则不如Go
- Go: 并发量越高,Go的表现与其他几个相比越好
- Java: 低并发不如Nodejs,高并发不如Go,但整体表现较好
- Python: ????
低并发: Nodejs > Go > Java
高并发: Go > Java > Nodejs
这只是一个极不严谨的测试,不供参考
建议自己调整一下压测的并发量体会一下
build-web-application-with-golang
Thank you !
2019.5 ShangHai @NIO-DataTeam