下面这段代码输出什么?为什么?
func main() {
var m = [...]int{1, 2, 3}
for i, v := range m {
go func() {
fmt.Println(i, v)
}()
}
time.Sleep(time.Second * 3)
}
下面这段代码输出什么?为什么?
func main() {
var m = [...]int{1, 2, 3}
for i, v := range m {
go func() {
fmt.Println(i, v)
}()
}
time.Sleep(time.Second * 3)
}
`单行代码`
执行结果不一定是这个吧?
按理说输出应该是执行到的那个goroutine时i,v的值,所以结果是不确定的。 比如说如果第一个goroutine执行的够快,当i,v的值为1,2时就输出了1,2的结果
疑问同上
其实你可以这么理解,就是每个协程在for range循环完了才启动,你可以试试,把数组的值调大点,他们输出的,就会向你说的那样,就是随机的。
打卡
我理解和你一样,例如在for内最后一行增加 time.Sleep(time.Microsecond * 5),有时会输出 0 1 2 3 2 3
di
mark
如果是题目中的这种情况是基本只会输出答案的结果了,携程的创建也需要时间,不会比短数组的for更快
很明显,闭包使用函数外变量会指针传递,而for循环这样写,所有 i,v都会指向同一个指针,等协程创建开始执行 的时候,i,v所指向的地址数据都已经是 2,3 了
打卡吧,总是感觉这个很诡异
这种写法不可取
m
协程用的不好,用的奇怪。会得到诡异的结果,协程间通信,还是要用chan
for range 里面的 i,v 接收数据的地址都保持不变 也就是说无论for 多少次,至始至终i, v分别的地址不会变,执行到最后一个3 i,v 就变成了 2, 3。所以打印的为2,3
m
#1楼说的对,不一定是答案解析的结果 具体原因的话,大家都懂,其实就是i、v一直是同一个地址,使用gorouine之后,读取的i、v都是从同一个地址读取的数据,但是,for循环会修改i、v的值,所以不是按顺序输出i、v的值,输出的是goroutine执行瞬间的数值 所以将数组的长度扩大,就会得到不同的结果,不一定是最后的数据
协程在for range之后才会启动,且i,v指向的是执行完range之后的具体值。
mark
2022-04-24
不一定
劳烦请教下
“协程在for range之后才会启动,且i,v指向的是执行完range之后的具体值。”--这个说法是错的 因为协程和for循环是并发的,也就是说“同时”在运行(这个“同时”是宏观上的含义),所以是for循环运行得比较快还是goroutine运行的比较快这个事情是不确定的
mark
0 1 ;1 2 ;2 3 。实际上输出3组,但是可能某组输出多个,某组不输出。最大概率是3组2 3 。原因是goroutine 还没起来,外层的循环就跑完了。 go func(i,v) { fmt.Println(i, v) }(i,v) 就没毛病了。 (golang码农求职)
打卡
mark
mark
mk
mark
mark。。。
卡
mark
协程
打卡
1111
mark
这个问题挺像js的for循环+异步操作的
mark
最大的概率未2,3 ,其中0,1 1,2 2,3 都有一定概率出现
打卡学习
for range 使用短变量声明 (:=) 的形式迭代变量,需要注意的是,变量 i、v 在每次循环体中都会被重用,而不是重新声明。
打卡学习
mark
mark
是这样 https://go.dev/play/p/zNJSQ9t2dzQ
闭包引用,使用的是上下文环境的值。两种可行的 fix 方法: a.使用函数传递 b.使用临时变量保留当前值
for range 循环遍历时创建的是数据的副本,而不是创建引用,所以一个引用多个数据共用,起到地址复用的功能,且由于闭包保留的是引用,而在 go 中,for range循环没有函数调用的前提下是不会标记为可抢占的状态,所以 go func(){}都是在循环结束后执行。所以此时 i,v 都是处于最后的数据状态。因此输出 2,3
学习
2.22 已经解决这个问题
go 1.22 解决了这个问题 ,go1.22 之前 也不一定是 这样 例如 https://go.dev/play/p/Hs2INcjMc2p?v=goprev