/images/hugo/avatar.png

Go reflect

1. 反射

Go在标准库中提供的reflect包让Go程序具备运行时的反射能力(reflection,又称为自省)。反射是程序在运行时访问、检测和修改它本身状态或行为的一种能力,各种编程语言所实现的反射机制各有不同。Go语言的interface{}类型变量具有析出任意类型变量的类型信息(type)和值信息(value)的能力,Go的反射本质上就是利用interface{}的这种能力在运行时对任意变量的类型和值信息进行检视甚至是对值进行修改的机制。

Go unsafe包的安全使用模式

1. 类型安全

在Go语言中,我们是无法通过常规语法手段穿透Go在类型系统层面对内存数据的保护的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
    a := 0x12345678
    fmt.Printf("0x%x\n", a)

    var p *byte = (*byte)(&a)   // 错误!不允许将&a从*int类型显式转型为*byte类型
    *p = 0x23

    var b byte = byte(a)        // b是一个新变量,有自己所解释的内存空间
    b = 0x23                    // 即便强制进行类型转换,原变量a所解释的内存空间的数据依然不变
    fmt.Printf("0x%x\n", b)     // 0x23
    fmt.Printf("0x%x\n", a)     // 0x12345678
}

Go在常规操作下是类型安全的(注:并非绝对的类型安全,绝对的类型安全需要在数学上的形式化证明)。所谓类型安全是指一块内存数据一旦被特定的类型所解释(该内存数据与该类型变量建立关联,也就是变量定义),它就不能再被解释为其他类型,不能再与其他类型变量建立关联。

Go 网络编程

Go是自带运行时的跨平台编程语言,Go中暴露给语言使用者的TCP Socket接口是建立在操作系统原生TCP Socket接口之上的。由于Go运行时调度的需要,Go设计了一套适合自己的TCP Socket网络编程模型。在本条中我们就来理解一下这个模型,并了解在该模型下Go TCP Socket在各个场景下的使用方法、行为特点及注意事项。

Go 调度器

今天我们来学习一些 Go 程序的调试技巧。

1. 调度器状态的查看方法

Go提供了调度器当前状态的查看方法:使用Go运行时环境变量GODEBUG。

1
2
3
4
5
6
$ GODEBUG=schedtrace=1000 godoc -http=:6060
SCHED 0ms: gomaxprocs=4 idleprocs=3 threads=3 spinningthreads=0 idlethreads=0 runqueue=0 [0 0 0 0]
SCHED 1001ms: gomaxprocs=4 idleprocs=0 threads=9 spinningthreads=0 idlethreads=3 runqueue=2 [8 14 5 2]
SCHED 2006ms: gomaxprocs=4 idleprocs=0 threads=25 spinningthreads=0 idlethreads=19 runqueue=12 [0 0 4 0]
SCHED 3006ms: gomaxprocs=4 idleprocs=0 threads=26 spinningthreads=0 idlethreads=8 runqueue=2 [0 1 1 0]
SCHED 4010ms: gomaxprocs=4 idleprocs=0 threads=26 spinningthreads=0 idlethreads=20 runqueue=12 [6 3 1 0]

GODEBUG 通过给其传入不同的key1=value1, key2=value2, …组合,Go的运行时会输出不同的调试信息,比如在这里我们给GODEBUG传入了"schedtrace=1000",其含义就是每1000ms打印输出一次goroutine调度器的状态,每次一行。以上面例子中最后一行为例,每一行各字段含义如下:

Go 汇编反汇编

1. 查看Go程序的汇编代码

查看Go程序的汇编代码有多种方法:

  1. 使用objdump工具:objdump -S go二进制文件
  2. 使用gdb disassemble
  3. 使用go tool工具生成汇编代码文件:go build -gcflags '-S' xx.go > xx.s 2>&1
  4. 将Go代码编译成汇编代码:go tool compile -S xx.go > xx.s
  5. 使用go tool工具反编译Go程序:go tool objdump -S go-binary > xx.s
1
2
3
4
// 编译
GOARCH=386 go tool compile -N -l test.go
// 反编译
GOARCH=386 go tool objdump -gnu test.o

交叉编译

1
2
3
4
GOOS=linux GOARCH=amd64 go build

// 交叉编译支持的所有架构
$GOROOT/src/go/build/syslist.go

参考资料

  1. Debugging Performance Issues in Go Programs
  2. go.dev/doc/diagnostics
  3. go-perfbook
  4. talk-yapc-asia-2015