如果我等待 WaitGroup 执行完毕再检查 pairs slice 的结果,我们可以预期到内容是完全相同的,虽然它的排序可能有些出入。gdb 真正的威力来自于它可以在 goroutines 正在运行时进行检查:
(gdb) b main.go:43
Breakpoint 1 at 0x400f7f: file /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/main.go, line 43.
(gdb) run
Starting program: /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/gdb_sandbox
Breakpoint 1, main.handleNumber (i=0, ~r1=0x0)
at /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/main.go:43
43 y: val,
(gdb) l
38 if i%2 == 0 {
39 val = f(i)
40 }
41 return &pair{
42 x: i,
43 y: val,
44 }
45 }
46
47 func f(x int) int {
(gdb) info args
i = 0
~r1 = 0x0
(gdb) p val
$1 = 0
你会发现我们在 goroutine 要执行的代码段中放置了一个断点,从这里我们可以检查到局部变量,和进程中的其它 goroutines:
(gdb) info goroutines
1 waiting runtime.gopark
2 waiting runtime.gopark
3 waiting runtime.gopark
4 waiting runtime.gopark
* 5 running main.main.func1
6 runnable main.main.func1
7 runnable main.main.func1
8 runnable main.main.func1
9 runnable main.main.func1
* 10 running main.main.func1
11 runnable main.main.func1
12 runnable main.main.func1
13 runnable main.main.func1
14 runnable main.main.func1
15 waiting runtime.gopark
(gdb) goroutine 11 bt
#0 main.main.func1 (val=6, pairChan=0xc82001a180, &wg=0xc82000a3a0)
at /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/main.go:19
#1 0x0000000000454991 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1696
#2 0x0000000000000006 in ?? ()
#3 0x000000c82001a180 in ?? ()
#4 0x000000c82000a3a0 in ?? ()
#5 0x0000000000000000 in ?? ()
(gdb) goroutine 11 l
48 return x*x + x
49 }
(gdb) goroutine 11 info args
val = 6
pairChan = 0xc82001a180
&wg = 0xc82000a3a0
(gdb) goroutine 11 p val
$2 = 6
在这里我们做的第一件事就是列出所有正在运行的 goroutine,并确定我们正在处理的那一个。然后我们可以看到一些回溯,并发送任何调试命令到 goroutine。这个回溯和列表清单并不太准确,如何让回溯更准确,goroutine 上的 info args 显示了我们的局部变量,以及主函数中的可用变量,goroutine 函数之外的使用前缀&。
结论
当调试应用时,gdb 的强大令人难以置信。但它仍然是一个相当新的事物,并不是所有的地方工作地都很完美。使用最新的稳定版 gdb,go 1.5 beta2,有不少地方有突破:
Interfaces根据 go 博客上的文章, go 的 interfaces 应该已经支持了,这允许在 gdb 中动态的投影其基类型。这应该算一个突破。
Interface{} 类型目前没有办法转换 interface{} 为它的类型。
列出 goroutine 的不同点在其他 goroutine 中列出周边代码会导致一些行数的漂移,最终导致 gdb 认为当前的行数超出文件范围并抛出一个错误:
(gdb) info goroutines
1 waiting runtime.gopark
2 waiting runtime.gopark
3 waiting runtime.gopark
4 waiting runtime.gopark
* 5 running main.main.func1
6 runnable main.main.func1
7 runnable main.main.func1
8 runnable main.main.func1
9 runnable main.main.func1
* 10 running main.main.func1
11 runnable main.main.func1
12 runnable main.main.func1
13 runnable main.main.func1
14 runnable main.main.func1
15 waiting runtime.gopark
(gdb) goroutine 11 bt
#0 main.main.func1 (val=6, pairChan=0xc82001a180, &wg=0xc82000a3a0)
at /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/main.go:19
#1 0x0000000000454991 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1696
#2 0x0000000000000006 in ?? ()
#3 0x000000c82001a180 in ?? ()
#4 0x000000c82000a3a0 in ?? ()
#5 0x0000000000000000 in ?? ()
(gdb) goroutine 11 l
48 return x*x + x
49 }
(gdb) goroutine 11 l