一道关于 goroutine 的面试题

问题

package main

import (
 "fmt"
 "time"
)

func main() {
    
    
 ch1 := make(chan int)
 go fmt.Println(<-ch1)
 ch1 <- 5
 time.Sleep(1 * time.Second)
}

问:
上面代码输出什么?

是5还是别的呢?

分析

如果代码换成如下:

package main

import (
 "fmt"
 "time"
)

func main() {
    
    
 ch1 := make(chan int)
  go func(){
    
    
    fmt.Println(<-ch1)
  }()
 ch1 <- 5
 time.Sleep(1 * time.Second)
}

答案:
上面问题是造成死锁
第二种情况是正常输出5

这里说明,go 语句后面的函数调用,其参数会先求值,这和普通的函数调用求值一样。
大意思是说,函数调用之前,实参就被求值好了。

因此这道题目 go fmt.Println(<-ch1) 语句中的 <-ch1 是在 main goroutine 中求值的。这相当于一个无缓冲的 chan,发送和接收操作都在一个 goroutine 中(main goroutine)进行,因此造成死锁。

更进一步,大家可以通过汇编看看上面两种方式的不同。

扩展

此外,defer 语句也要注意。比如下面的做法是不对的:

defer recover()

而应该使用这样的方式:

 defer func() {
    
    
  if v := recover(); v != nil {
    
    
   _ = fmt.Errorf("PANIC=%v", v)
  }
 }()

猜你喜欢

转载自blog.csdn.net/csdniter/article/details/112968783
今日推荐