面试问题浓缩总结 面试问题浓缩总结
  • Go
  • Java
  • C/C++
  • JavaScript/HTML
  • MySQL
  • Redis
  • MongoDB
  • 操作系统
  • 计算机网络
  • spring全家桶
  • mybatis
  • 中间件
  • 软件相关
  • 系统相关
  • 算法
  • 数据结构
  • 设计模式
  • CMU硕士经典100题
  • 剑指offer
  • 重点手撕代码
  • 程序员面试金典
  • 3月
  • 4月
  • 智力题
  • 业务问题
  • 一些技术
  • 安全相关
APP下载 (opens new window)
GitHub (opens new window)
  • Go
  • Java
  • C/C++
  • JavaScript/HTML
  • MySQL
  • Redis
  • MongoDB
  • 操作系统
  • 计算机网络
  • spring全家桶
  • mybatis
  • 中间件
  • 软件相关
  • 系统相关
  • 算法
  • 数据结构
  • 设计模式
  • CMU硕士经典100题
  • 剑指offer
  • 重点手撕代码
  • 程序员面试金典
  • 3月
  • 4月
  • 智力题
  • 业务问题
  • 一些技术
  • 安全相关
APP下载 (opens new window)
GitHub (opens new window)
  • Go

    • 编译原理
    • 数据结构
    • 语言基础
    • 常用关键字
    • 并发编程
    • 内存管理
    • 元编程
    • 标准库
    • 其他
      • Go的基本命令
      • 利用CPU缓存优化Go程序
      • Go内存对齐
      • unsafe包
      • gdb和pprof使用
      • sync.Pool原理
    • 面试问题
  • JAVA

  • C、C++语言

  • JavaScript和HTML

  • Android相关

  • 程序语言
  • Go
小游
2021-03-27

其他

# Go的基本命令

// 用于打包编译代码
go build
// 来移除当前源码包和关联源码包里面编译生成的文件
go clean
// 格式化代码文件
go fmt
// 下载安装包
go get
// 这里就是先生成结果文件,然后把这个文件放到我们的包里面去
go install
// 测试文件自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件
go test
// go提供的一些工具
go tool fix //用来修复以前老版本的代码到新版本
go tool vet directory|files  //用来分析当前目录的代码是否都是正确的代码
// 用于在编译前自动化生成某类代码。go generate和go build是完全不一样的命令,通过分析源码中特殊的注释,然后执行相应的命令。这些命令都是很明确的,没有任何的依赖在里面。而且大家在用这个之前心里面一定要有一个理念,这个go generate是给你用的,不是给使用你这个包的人用的,是方便你来生成一些代码的。
go generate
// 生成文档
go doc
go version 查看go当前的版本
go env 查看当前go的环境变量
go list 列出当前全部安装的package
go run 编译并运行Go程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

参考 Go 基本命令_kf_panda-CSDN博客 (opens new window)

# 利用CPU缓存优化Go程序

常见问题就是下面那段代码执行速度更快

func createMatrix(size int) [][]int64 {
    matrix := make([][]int64, size)
    for i := 0; i < size; i++ {
        matrix[i] = make([]int64, size)
    }
    return matrix
}
const matrixLength = 6400
func BenchmarkMatrixCombination(b *testing.B) {
    matrixA := createMatrix(matrixLength)
    matrixB := createMatrix(matrixLength)
    for n := 0; n < b.N; n++ {
        for i := 0; i < matrixLength; i++ {
            for j := 0; j < matrixLength; j++ {
                matrixA[i][j] = matrixA[i][j] + matrixB[i][j]
            }
        }
    }
}
func BenchmarkMatrixReversedCombination(b *testing.B) {
    matrixA := createMatrix(matrixLength)
    matrixB := createMatrix(matrixLength)
    for n := 0; n < b.N; n++ {
        for i := 0; i < matrixLength; i++ {
            for j := 0; j < matrixLength; j++ {
                matrixA[i][j] = matrixA[i][j] + matrixB[j][i]
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

我们可以看到前面的速度会比后面的块10倍

BenchmarkMatrixCombination-8                     16      67211689 ns/op
BenchmarkMatrixReversedCombination-8              3     480798925 ns/op
1
2

简单点说就是第一种方式访问时,我们的数据会缓存到cache line中,这样可以加快查找速度

image.png

参考:

CPU缓存体系对Go程序的影响 - SegmentFault 思否 (opens new window)

# Go内存对齐

什么是内存对齐

struct 中的字段顺序不同,内存占用也有可能会相差很大,比如下面这段代码

type T1 struct {
	a int8
	b int64
	c int16
}

type T2 struct {
	a int8
	c int16
	b int64
}
1
2
3
4
5
6
7
8
9
10
11

在 64 bit 平台上,T1 占用 24 bytes,T2 占用 16 bytes 大小;而在 32 bit 平台上,T1 占用 16 bytes,T2 占用 12 bytes 大小。可见不同的字段顺序,最终决定 struct 的内存大小,所以有时候合理的字段顺序可以减少内存的开销。

因为64位的平台上,我们每次读取都是按字节来读取的,一个字节就是8位,比如我们的T1,在64位系统就会因为padding导致多占用了内存

img

而T2因为内存对其了,所以比上面少了8个字节

img

  • 你正在编写的代码在性能(CPU、Memory)方面有一定的要求

  • 你正在处理向量方面的指令

  • 某些硬件平台(ARM)体系不支持未对齐的内存访问

  • 平台(移植性)原因:不是所有的硬件平台都能够访问任意地址上的任意数据。例如:特定的硬件平台只允许在特定地址获取特定类型的数据,否则会导致异常情况

  • 性能原因:若访问未对齐的内存,将会导致 CPU 进行两次内存访问,并且要花费额外的时钟周期来处理对齐及运算。而本身就对齐的内存仅需要一次访问就可以完成读取动作

参考:

  1. 在 Go 中恰到好处的内存对齐 - 知乎 (zhihu.com) (opens new window)
  2. Golang 是否有必要内存对齐? - poslua | ms2008 Blog (opens new window)

# unsafe包

golang是一种静态的强类型的语言,所有的类型都是不能随意转换的,Go语言是不允许两个指针类型进行转换的。go官方是不推荐使用unsafe的操作因为它是不安全的,它绕过了golang的内存安全原则,容易使你的程序出现莫名其妙的问题,不利于程序的扩展与维护。但是在很多地方却是很实用。在一些go底层的包中unsafe包被很频繁的使用。

Go unsafe 包的使用 - SegmentFault 思否 (opens new window)

# gdb和pprof使用

gdb是用来调试go程序的,pprof是用于监控程序性能的

# sync.Pool原理

这个东西可以用来缓存对象,来减轻GC消耗

sync.Pool 是 sync 包下的一个组件,可以作为保存临时取还对象的一个“池子”。个人觉得它的名字有一定的误导性,因为 Pool 里装的对象可以被无通知地被回收,可能 sync.Cache 是一个更合适的名字。

有啥用

对于很多需要重复分配、回收内存的地方,sync.Pool 是一个很好的选择。频繁地分配、回收内存会给 GC 带来一定的负担,严重的时候会引起 CPU 的毛刺,而 sync.Pool 可以将暂时不用的对象缓存起来,待下次需要的时候直接使用,不用再次经过内存分配,复用对象的内存,减轻 GC 的压力,提升系统的性能。

如何使用

package main
import (
	"fmt"
	"sync"
)
var pool *sync.Pool
type Person struct {
	Name string
}
func initPool() {
	pool = &sync.Pool {
		New: func()interface{} {
			fmt.Println("Creating a new Person")
			return new(Person)
		},
	}
}
func main() {
	initPool()
	p := pool.Get().(*Person)
	fmt.Println("首次从 pool 里获取:", p)
	p.Name = "first"
	fmt.Printf("设置 p.Name = %s\n", p.Name)
	pool.Put(p)
	fmt.Println("Pool 里已有一个对象:&{first},调用 Get: ", pool.Get().(*Person))
	fmt.Println("Pool 没有对象了,调用 Get: ", pool.Get().(*Person))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

深度解密 Go 语言之 sync.Pool - Stefno - 博客园 (cnblogs.com) (opens new window)

编辑 (opens new window)
上次更新: 2021/04/20, 22:11:56
标准库
面试问题

← 标准库 面试问题→

Theme by Vdoing | Copyright © 2021-2021 小游
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式