1. Golang

Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。

Go的语法接近C语言,但对于变量的声明有所不同。Go支持垃圾回收功能。

与C++相比,Go并不包括如枚举、异常处理、继承、泛型、断言、虚函数等功能,但增加了 切片(Slice) 型、并发、管道、垃圾回收、接口(Interface)等特性的语言级支持。


2. Golang资料补给包

包含文章,书籍,作者论文,理论分析,开源框架,云原生,大佬视频,大厂实战分享ppt


3. Go 语言用途

Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。

对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。


4. golang适合做什么

  • 1.云计算基础设施领域

代表项目:docker、kubernetes、etcd、consul、cloudflare cdn、七牛云存储等

  • 2.基础后端软件

代表项目:tidb、influxdb,cockroachdb

  • 3.微服务

代表项目: go-kit、micro、monzo bank的typhon、bilibili等

  • 4.互联网基础设施

代表项目:以太坊、hyperledger等

  • 5. golang的缺点有哪些?

1.包管理,大部分都在github上,私人账户维护,风险较大

2.无泛化类型,go 2.0计划加上

3.所有的exception都用Error来处理

4.对C的降级处理,并非无缝,没有C降级到asm那么完美(序列化问题)


  • 6. golang cpu性能分析

6.1 分析程序的运行时间

time指令(linux系统下)

  • real:从程序开始到结束,实际上度过的时间
  • user:程序在用户态度过的时间
  • sys:程序在内核度过的时间

一般情况下,real>=user+sys

/usr/bin/time 指令(linux系统下)

该指令下 可以看到 cpu占用率、 内存使用情况、 进程切换情况 、文件系统io、socket情况


6.2 golang下cpu性能分析

(1)在程序中引入 _ "net/http/pprof" ,并开启pprof监听


通过浏览器查看 CPU的信息和状态。


通过浏览器查看 CPU的信息和状态

注意,等程序运⾏⼀定时间,再点击profile⽂件⽣成(⾄少是30s)


(2)使用pprof

  • flat 该函数⾃身代码的执⾏时⻓
  • flat% 该函数⾃身代码的执⾏时⻓占⽤CPU的耗时百分⽐
  • cum 代表的是该函数⾃身代码+所有调⽤的函数的执⾏时⻓
  • cum% 代表的是该函数⾃身代码+所有调⽤的函数的执⾏时⻓,占⽤CPU的总耗时百分⽐
  • sum% 每⼀⾏的flat%与上⾯所有⾏的flat%总和

(3)go tool pprof profile文件

启动要调试的程序,在另一个终端执行 go tool pprof http://localhost:10000/debug/pprof/profile?seconds=60


(4)可视化结构图


7. golang 程序内存分析方法

(1)内存的占⽤情况 top -p $(pidof 进程名) 查看某个进程的内存占⽤情况

(2)GODEBUG和gctrace来分析golang程序的内存使用情况

输出的GC数据 gc 17 @0.512s 2%: 0.003+33+0.003 ms clock, 0.007+0/0.053/33+0.007 ms cpu, 181->181->101 MB, 182 MB goal, 2 P


数据中每个的字段含义:

  • gc 17 表示GC回收的次数编号,递增
  • @0.512s 当前程序已经执⾏了0.512s
  • 2% 0.512s中其中gc模块占⽤了2%的时间
  • 0.003+33+0.003 ms clock 垃圾回收的时间,分别为STW(Stop the world)的时间+并发标记的时间+STW标记的时间

两次回收过程:

将444MB活跃的内存标记为⾮活跃内存, 全局堆内存增加到888MB gc 21 @0.465s 0%: 0.004+0.12+0.003 ms clock, 0.009+0/0.017/0.064+0.006 ms cpu, 444->444->0 MB, 888 MB goal, 2 P (forced)

将888MB的垃圾内存,全部的清除掉 gc 22 @121.396s 0%: 0.007+0.090+0.002 ms clock, 0.014+0/0.025/0.084+0.005 ms cpu, 0->0->0 MB, 4 MB goal, 2 P


(3)runtime.MemStats调试当前 golang程序内存的占⽤情况

在代码中定义runtime.MemStats 对象来查看


  • 1. Alloc uint64 //golang语⾔框架堆空间分配的字节数
  • 2. TotalAlloc uint64 //从服务开始运⾏⾄今分配器为分配的堆空间总 和,只有增加,释放的时候不减少
  • 3. Sys uint64 //服务现在系统使⽤的内存
  • 4. Lookups uint64 //被runtime监视的指针数
  • 5. Mallocs uint64 //服务malloc heap objects的次数
  • 6. Frees uint64 //服务回收的heap objects的次数
  • 7. HeapAlloc uint64 //服务分配的堆内存字节数
  • 8. HeapSys uint64 //系统分配的作为运⾏栈的内存
  • 9. HeapIdle uint64 //申请但是未分配的堆内存或者回收了的堆内存(空闲)字节数
  • 10. HeapInuse uint64 //正在使⽤的堆内存字节数
  • 10. HeapReleased uint64 //返回给OS的堆内存,类似C/C++中的free。
  • 11. HeapObjects uint64 //堆内存块申请的量
  • 12. StackInuse uint64 //正在使⽤的栈字节数
  • 13. StackSys uint64 //系统分配的作为运⾏栈的内存
  • 14. MSpanInuse uint64 //⽤于测试⽤的结构体使⽤的字节数
  • 15. MSpanSys uint64 //系统为测试⽤的结构体分配的字节数
  • 16. MCacheInuse uint64 //mcache结构体申请的字节数(不会被视为垃圾回收)
  • 17. MCacheSys uint64 //操作系统申请的堆空间⽤于mcache的字节数
  • 18. BuckHashSys uint64 //⽤于剖析桶散列表的堆空间
  • 19. GCSys uint64 //垃圾回收标记元信息使⽤的内存
  • 20. OtherSys uint64 //golang系统架构占⽤的额外空间
  • 21. NextGC uint64 //垃圾回收器检视的内存⼤⼩
  • 22. LastGC uint64 // 垃圾回收器最后⼀次执⾏时间。
  • 23. PauseTotalNs uint64 // 垃圾回收或者其他信息收集导致服务暂停的次数。
  • 24. PauseNs [256]uint64 //⼀个循环队列,记录最近垃圾回收系统中断的时间
  • 25. PauseEnd [256]uint64 //⼀个循环队列,记录最近垃圾回收系统中断的时间开始点。
  • 26. NumForcedGC uint32 //服务调⽤runtime.GC()强制使⽤垃圾回收的次数。
  • 27. GCCPUFraction float64 //垃圾回收占⽤服务CPU⼯作的时间总和。如果有100个goroutine,垃圾回收的时间为1S,那么就占⽤了
  • 100S。
  • 28. BySize //内存分配器使⽤情况


(4)pprof分析golang内存

在被调试的程序中,提供⼀个 web端⼝ 在main函数中添加⼀个端⼝监听

通过浏览器⽹⻚来查看内存的信息和状态



8. golang面试题知识点总结

数据定义

1.函数返回值问题:

在函数有多个返回值时,只要有⼀个返回值有名 称,那么其他返回值也⼀定要有名称


2.结构体的⽐较问题 :

结构体⽐较规则之⼀: 只有相同的类型的结构体才可以⽐较(1 结构体的属性类型, 2 属性的顺序)

结构体⽐较规则之⼆: 即使两个结构体的属性类型和顺序相同,但是⾥⾯存在不可⽐较类型,依然是不可以直接==⽐较的。 ⽐如 map,slice 可以参考⽤reflect.DeepEqual⽅法来进⾏⽐较


3.string与nil类型的问题

nil空值的赋值

空值, 空指针,所有Golang中的引⽤类型都可以⽤nil进⾏赋值 引⽤类型: interface , function, pointer, map, slice, channel.

string: 如果表示⼀个string的空值, ⽤空字符串来表示 ""

不能够将nil赋值给⼀个string类型


4.常量的问题

数据类型的本质 固定内存⼤⼩的别名

数据类型的作⽤ 编译器预算对象或变量分配内存空间的⼤⼩


内存四区:

(1)栈区

空间较⼩,要求数据读写性能⾼,数据存放时间较短暂。由编译器⾃动分配和释 放,存放函数的参数值、函数的调⽤流程⽅法地址、局部变量等(局部变量如果 产⽣逃逸现象,可能会挂在在堆区)


(2)堆区

空间充裕,数据存放时间较久。⼀般由开发者分配及释放(但是Golang中会根据 变量的逃逸现象来选择是否分配到栈上或堆上),启动Golang的GC由GC清除机 制⾃动回收。


(3)全局区

静态全局变量区 全局变量的开辟是在程序在main之前就已经放在内存中。⽽且对 外完全可⻅。即作⽤域在全部代码中,任何同包代码均可随时使 ⽤,在变量会搞混淆,⽽且在局部函数中如果同名称变量使⽤:=赋 值会出现编译错误。

常量区 常量区也归属于全局区,常量为存放数值字⾯值单位,即不 可修改。或者说的有的常量是直接挂钩字⾯值的。 const cl = 10 cl是字⾯量10的对等符号。


(4)代码区

存放代码逻辑的内存


数组与切⽚

(1)切⽚的初始化和追加:

slice在经过make初始化,默认的数据的值是0,append 是动态额外开辟内存。

(2)slice拼接问题:

两个slice在append的时候,记住需要进⾏将第⼆个slice进⾏...打散再拼接。s1 = append(s1, s2...)

(3)slice中new的使⽤问题

make只⽤于slice、map以及channel的初始化(⾮零值);make返回的还是这三个引⽤类型本身; ⽽new⽤于类型的内存分配,并且内存置为零;⽽new返回的是指向类型的指针。


不建议⽤new来开辟slice , map 和 channel


Map

(1)map的value赋值问题

定义map不推荐 map[string]Student map的value student⾥的属性是不可以修改的

推荐 map[string]*Student map的value student的属性是可以修改的

(2)map遍历问题

遍历map 不推荐 //将数组依次添加到map中 for _, stu := range stus { m[stu.Name] = &stu } //遍历map的时候,不要采⽤range的⽅式来遍历

推荐 //遍历整个slice数组,⼀次赋值给map for i := 0; i < len(stus); i++ { m[stus[i].Name] = &stus[i] }


interface

(1)interface的赋值

多态的三要素


有interface接⼝,并且有接⼝定义的⽅法。

有⼦类去重写interface的接⼝。

有⽗类指针指向⼦类的具体对象

如果People是⼀个interface类型 var peo People = Stduent{} 错误的

var peo People = &Student{} 正确的


(2)interface的内部构造


空接口:


非空接口:


(3)interface{} 和 interface{}

interface{}本身不是万能指针, 就是eface结构体的地址。

如果以interface{}作为形参,那么他只能够接收interface{}类型的实参。


channel

channel出现的特殊情况总结

  • 给⼀个 nil channel 发送数据,造成永远阻塞
  • 从⼀个 nil channel 接收数据,造成永远阻塞
  • 给⼀个已经关闭的 channel 发送数据,引起 panic
  • 从⼀个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回⼀个零值
  • ⽆缓冲的channel是同步的,⽽有缓冲的channel是⾮同步的


15字⼝诀: 空(nil)读写阻塞,写关闭异常,读关闭空零


WaitGroup