defer

1

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. defer_call()
  7. }
  8. func defer_call() {
  9. defer func() { fmt.Println("打印前") }()
  10. defer func() { fmt.Println("打印中") }()
  11. defer func() { fmt.Println("打印后") }()
  12. panic("触发异常")
  13. }
  14. // 后、中、前 异常

defer 关键字的实现跟go关键字很类似,不同的是它调用的是runtime.deferproc而不是runtime.newproc

defer出现的地方,插入了指令call runtime.deferproc,然后在函数返回之前的地方,插入指令call runtime.deferreturn

goroutine的控制结构中,有一张表记录defer,调用runtime.deferproc时会将需要defer的表达式记录在表中,而在调用runtime.deferreturn的时候,则会依次从defer表中出栈并执行。

因此,题目最后输出顺序应该是defer 定义顺序的倒序。panic 错误并不能终止 defer 的执行。

2

  1. func hello(i int) {
  2. fmt.Println(i)
  3. }
  4. func main() {
  5. i := 5
  6. defer hello(i)
  7. i = i + 10
  8. }

5。这个例子中,hello() 函数的参数在执行 defer 语句的时候会保存一份副本,在实际调用 hello() 函数时用,所以是 5.

函数

1

  1. func hello() []string {
  2. return nil
  3. }
  4. func main() {
  5. h := hello
  6. if h == nil {
  7. fmt.Println("nil")
  8. } else {
  9. fmt.Println("not nil")
  10. }
  11. }
  • A. nil
  • B. not nil
  • C. compilation error

B。这道题目里面,是将 hello() 赋值给变量 h,而不是函数的返回值,所以输出 not nil。

实现set

  1. type inter interface{}
  2. type Set struct {
  3. m map[inter]bool
  4. sync.RWMutex
  5. }
  6. func New() *Set {
  7. return &Set{
  8. m: map[inter]bool{},
  9. }
  10. }
  11. func (s *Set) Add(item inter) {
  12. s.Lock()
  13. defer s.Unlock()
  14. s.m[item] = true
  15. }

一些简单方法控制goroutines数量

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. "runtime"
  6. )
  7. func busi(ch chan bool, i int) {
  8. fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine())
  9. <-ch
  10. }
  11. func main() {
  12. //模拟用户需求业务的数量
  13. task_cnt := math.MaxInt64
  14. //task_cnt := 10
  15. ch := make(chan bool, 3)
  16. for i := 0; i < task_cnt; i++ {
  17. ch <- true
  18. go busi(ch, i)
  19. }
  20. }

channel与sync同步组合方式

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. "sync"
  6. "runtime"
  7. )
  8. var wg = sync.WaitGroup{}
  9. func busi(ch chan bool, i int) {
  10. fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine())
  11. <-ch
  12. wg.Done()
  13. }
  14. func main() {
  15. //模拟用户需求go业务的数量
  16. task_cnt := math.MaxInt64
  17. ch := make(chan bool, 3)
  18. for i := 0; i < task_cnt; i++ {
  19. wg.Add(1)
  20. ch <- true
  21. go busi(ch, i)
  22. }
  23. wg.Wait()
  24. }

利用无缓冲channel与任务发送/执行分离方式

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. "sync"
  6. "runtime"
  7. )
  8. var wg = sync.WaitGroup{}
  9. func busi(ch chan int) {
  10. for t := range ch {
  11. fmt.Println("go task = ", t, ", goroutine count = ", runtime.NumGoroutine())
  12. wg.Done()
  13. }
  14. }
  15. func sendTask(task int, ch chan int) {
  16. wg.Add(1)
  17. ch <- task
  18. }
  19. func main() {
  20. ch := make(chan int) //无buffer channel
  21. goCnt := 3 //启动goroutine的数量
  22. for i := 0; i < goCnt; i++ {
  23. //启动go
  24. go busi(ch)
  25. }
  26. taskCnt := math.MaxInt64 //模拟用户需求业务的数量
  27. for t := 0; t < taskCnt; t++ {
  28. //发送任务
  29. sendTask(t, ch)
  30. }
  31. wg.Wait()
  32. }