Go每日一题(99) 的题目如下

4113 次点击 · 3 赞 ·大约8小时之前 开始浏览   · 来源「Golang来啦」

下面这段代码输出什么?为什么?

func main() {

	var m = [...]int{1, 2, 3}

	for i, v := range m {
		go func() {
			fmt.Println(i, v)
		}()
	}

	time.Sleep(time.Second * 3)
}
4113 阅读
50 回复
chenzhg
chenzhg · #1 · 3年之前

执行结果不一定是这个吧?

2 3
2 3
2 3

按理说输出应该是执行到的那个goroutine时i,v的值,所以结果是不确定的。 比如说如果第一个goroutine执行的够快,当i,v的值为1,2时就输出了1,2的结果

henry1
henry1 · #2 · 3年之前

疑问同上

577961141
577961141 · #3 · 3年之前
chenzhgchenzhg #1 回复

执行结果不一定是这个吧? ``` 2 3 2 3 2 3 ``` 按理说输出应该是执行到的那个goroutine时i,v的值,所以结果是不确定的。 比如说如果第一个goroutine执行的够快,当i,v的值为1,2时就输出了1,2的结果

其实你可以这么理解,就是每个协程在for range循环完了才启动,你可以试试,把数组的值调大点,他们输出的,就会向你说的那样,就是随机的。

euibieur894
euibieur894 · #4 · 3年之前

打卡

dingweihua
dingweihua · #5 · 3年之前
chenzhgchenzhg #1 回复

执行结果不一定是这个吧? ``` 2 3 2 3 2 3 ``` 按理说输出应该是执行到的那个goroutine时i,v的值,所以结果是不确定的。 比如说如果第一个goroutine执行的够快,当i,v的值为1,2时就输出了1,2的结果

我理解和你一样,例如在for内最后一行增加 time.Sleep(time.Microsecond * 5),有时会输出 0 1 2 3 2 3

minQie
minQie · #6 · 3年之前

di

neil_liu
neil_liu · #7 · 3年之前

mark

_Aiden_
_Aiden_ · #8 · 3年之前

如果是题目中的这种情况是基本只会输出答案的结果了,携程的创建也需要时间,不会比短数组的for更快

wi-cuckoo
wi-cuckoo · #9 · 3年之前

很明显,闭包使用函数外变量会指针传递,而for循环这样写,所有 i,v都会指向同一个指针,等协程创建开始执行 的时候,i,v所指向的地址数据都已经是 2,3 了

droice
droice · #10 · 3年之前

打卡吧,总是感觉这个很诡异

droice
droice · #11 · 3年之前
droicedroice #10 回复

打卡吧,总是感觉这个很诡异

这种写法不可取

halo_young
halo_young · #12 · 3年之前

m

gonglf
gonglf · #13 · 3年之前

协程用的不好,用的奇怪。会得到诡异的结果,协程间通信,还是要用chan

huhaophp
huhaophp · #14 · 3年之前

for range 里面的 i,v 接收数据的地址都保持不变 也就是说无论for 多少次,至始至终i, v分别的地址不会变,执行到最后一个3 i,v 就变成了 2, 3。所以打印的为2,3

    arr := []int{1, 2, 3, 4}
    for k, v := range arr {
        log.Println(&k, &v)
    }
2022/04/24 15:11:24 0xc0000b2008 0xc0000b2010
2022/04/24 15:11:24 0xc0000b2008 0xc0000b2010
2022/04/24 15:11:24 0xc0000b2008 0xc0000b2010
2022/04/24 15:11:24 0xc0000b2008 0xc0000b2010
Inforleo
Inforleo · #15 · 3年之前

m

golang_xuetu
golang_xuetu · #16 · 3年之前

#1楼说的对,不一定是答案解析的结果 具体原因的话,大家都懂,其实就是i、v一直是同一个地址,使用gorouine之后,读取的i、v都是从同一个地址读取的数据,但是,for循环会修改i、v的值,所以不是按顺序输出i、v的值,输出的是goroutine执行瞬间的数值 所以将数组的长度扩大,就会得到不同的结果,不一定是最后的数据

cpipi1024
cpipi1024 · #17 · 3年之前

协程在for range之后才会启动,且i,v指向的是执行完range之后的具体值。

Natsuwau
Natsuwau · #18 · 3年之前

mark

johann1024
johann1024 · #19 · 3年之前

2022-04-24

chenzhg
chenzhg · #20 · 3年之前
cpipi1024cpipi1024 #17 回复

协程在for range之后才会启动,且i,v指向的是执行完range之后的具体值。

不一定

cpipi1024
cpipi1024 · #21 · 3年之前
chenzhgchenzhg #20 回复

#17楼 @cpipi1024 不一定

劳烦请教下

chenzhg
chenzhg · #22 · 3年之前
cpipi1024cpipi1024 #21 回复

#20楼 @chenzhg 劳烦请教下

“协程在for range之后才会启动,且i,v指向的是执行完range之后的具体值。”--这个说法是错的 因为协程和for循环是并发的,也就是说“同时”在运行(这个“同时”是宏观上的含义),所以是for循环运行得比较快还是goroutine运行的比较快这个事情是不确定的

AntonyZhang
AntonyZhang · #23 · 3年之前

mark

brothersam
brothersam · #24 · 3年之前

0 1 ;1 2 ;2 3 。实际上输出3组,但是可能某组输出多个,某组不输出。最大概率是3组2 3 。原因是goroutine 还没起来,外层的循环就跑完了。 go func(i,v) { fmt.Println(i, v) }(i,v) 就没毛病了。 (golang码农求职)

hypersus
hypersus · #25 · 3年之前

打卡

hasbug
hasbug · #26 · 3年之前

mark

neil_liu
neil_liu · #27 · 3年之前

mark

NovaChaos
NovaChaos · #28 · 3年之前

mk

Zuos
Zuos · #29 · 3年之前

mark

a406299736
a406299736 · #30 · 3年之前

mark。。。

droice
droice · #31 · 3年之前

summers
summers · #32 · 3年之前

mark

QRQRQRqrqr
QRQRQRqrqr · #33 · 3年之前

协程

zhangyanping
zhangyanping · #34 · 2年之前

打卡

a406299736
a406299736 · #35 · 2年之前

1111

Yt3134
Yt3134 · #36 · 2年之前

mark

huanfengnt
huanfengnt · #37 · 2年之前

这个问题挺像js的for循环+异步操作的

hasbug
hasbug · #38 · 2年之前

mark

owen
owen · #39 · 2年之前

最大的概率未2,3 ,其中0,1 1,2 2,3 都有一定概率出现

hades2013
hades2013 · #40 · 2年之前

打卡学习

feiyang
feiyang · #41 · 2年之前

for range 使用短变量声明 (:=) 的形式迭代变量,需要注意的是,变量 i、v 在每次循环体中都会被重用,而不是重新声明。

huangyf168
huangyf168 · #42 · 2年之前

打卡学习

flyZ
flyZ · #43 · 2年之前

mark

hasbug
hasbug · #44 · 2年之前

mark

YuPeng
YuPeng · #45 · 2年之前
chenzhgchenzhg #1 回复

执行结果不一定是这个吧? ``` 2 3 2 3 2 3 ``` 按理说输出应该是执行到的那个goroutine时i,v的值,所以结果是不确定的。 比如说如果第一个goroutine执行的够快,当i,v的值为1,2时就输出了1,2的结果

feiyang
feiyang · #46 · 2年之前

闭包引用,使用的是上下文环境的值。两种可行的 fix 方法: a.使用函数传递 b.使用临时变量保留当前值

amocea
amocea · #47 · 大约1年之前

for range 循环遍历时创建的是数据的副本,而不是创建引用,所以一个引用多个数据共用,起到地址复用的功能,且由于闭包保留的是引用,而在 go 中,for range循环没有函数调用的前提下是不会标记为可抢占的状态,所以 go func(){}都是在循环结束后执行。所以此时 i,v 都是处于最后的数据状态。因此输出 2,3

cllgeek
cllgeek · #48 · 大约1年之前

学习

haha_cat
haha_cat · #49 · 9月之前

2.22 已经解决这个问题

YuPeng
YuPeng · #50 · 9月之前

go 1.22 解决了这个问题 ,go1.22 之前 也不一定是 这样 例如 https://go.dev/play/p/Hs2INcjMc2p?v=goprev

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传