在Go中可以直接通过go关键字直接创建一个goroutine并在子goroutine中直接调用函数;
但是有时候由于调用的方式不同会存在一些问题;
源代码:
Go创建Goroutine时显式调用时的坑
Goroutine调用概述
对于go关键字创建新goroutine并调用函数的方式有两种:
- 隐式传参调用
- 显式传参调用
1 | func main() { |
两者的区别在于:
- 当隐式传参时:此时传入的是x的“引用值”,即两个x指向的是同一个内存地址,在子routine中修改的值,会改变外部的x!
- 当显式传参时:此时为值传递,内部的x不会影响外部的x;
另外,需要注意的:显式的传参,在传参时就必须将参数计算好,这一点和defer函数是相同的!
例如:
1 | func main() { |
上面的函数大概率输出为:
1 | Direct invoke: 1 |
这是因为,在直接传参调用时,x的值还未被修改(仍然是1)并且已经被确定,而隐式传参调用会根据外部x值的改变而改变;
之所以说是
大概率是因为,一般情况下,隐式传参调用的goroutine执行速度还是比main中执行至x=3语句要慢的,所以,大概率会先执行x=3修改x的值,随后才会执行隐式传参调用!
一道关于 Goroutine 的题
下面的代码输出什么呢?
1 | package main |
以上代码输出什么?(单选)
- A:5
- B:不能编译
- C:运行时死锁
如果你耐心看了上面的讲解,可以很容易知道正确答案是:C;
因为:
在上方创建Goroutine进行调用时,实际上是显式传参!
所以,上方的代码其实类似于:
1 | func main() { |
此时x := <-ch1会阻塞main函数,而ch1 <- 5也是在main函数中调用的,所以会被阻塞,最终造成死锁!
附录
Goroutine题目来源:
源代码: