Skip to content

Latest commit

 

History

History
645 lines (492 loc) · 14.6 KB

1.md

File metadata and controls

645 lines (492 loc) · 14.6 KB

Running in Go: 1. 简介

希望通过本次分享能使大家对 Go 这门语言有个初步的认识

什么是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")

不允许声明变量但是不使用,否则编译不通过

Internal packages

优缺点

优点:

  • 编译速度快,直接编译成二进制可执行文件
  • 静态链接
  • 丰富的标准库
  • 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 Java Nodejs Python

  • Go v1.10
  • Nodejs v8.11
  • Python v3.4
  • Java jdk-v1.8

用abtest简单做一下测试, 10w 请求 1k 并发

服务器 centos7 4c 16g

Java

@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

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)

Go

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)

Python3

#!/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

这只是一个极不严谨的测试,不供参考

建议自己调整一下压测的并发量体会一下

也可以参考这里的GO性能

References

golang.org

awesome-go

build-web-application-with-golang

《The Way to Go》翻译

Go 知识图谱

golang-project-layout

go-best-practice

End

Thank you !

2019.5 ShangHai @NIO-DataTeam