Golang Go语言中 for loop 中的 gocoroutine 的问题

发布于 1周前 作者 bupafengyu 来自 Go语言

Golang Go语言中 for loop 中的 gocoroutine 的问题

刚开始用 go, 习惯 Java 了, 不小心踩了一个坑.
本意是 print 0 到 9 的. 虽然通过加参数解决了, 但是为啥会这样呢?
fmt.Printf(“go i=%d\n”, i) 这里面 i 的值是怎么获得的, 和 for 共享吗?
请指教下, 多谢了

	for i := 0; i < 10; i++ {
		go func() {
			fmt.Printf("go i=%d\n", i)
		}()
	}

更多关于Golang Go语言中 for loop 中的 gocoroutine 的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

12 回复

go func(num int){
// print after create
}(i)

更多关于Golang Go语言中 for loop 中的 gocoroutine 的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


package main

import (
“fmt”
“sync”
)

func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
fmt.Printf(“go i=%d\n”, i)
wg.Done()
}(i)
}

wg.Wait()
}

go i=9
go i=5
go i=6
go i=7
go i=8
go i=2
go i=3
go i=0
go i=1
go i=4

感谢两位, 其实

可能没说太清楚, 搞混的和 kotlin
for (i in 1…10) {
executor.submit { println(i) }
}
kotlin 这样是没有问题的.
既然 go func() {}() 没有参数 fmt.Printf(“go i=%d\n”, i) 这里面 i 的值是怎么获得的, 和 for 共享吗?
还有就是 go 执行顺序
可能 go scope 和 gocoroutine 机制的问题吧, 有空多研究下吧

go 的命令可以理解为生成 goroutine 包含一个上下文,把 i 引入了上下文中。当 goroutine 需要运行时,才会调用上下文中的 i 的值。此时可能 i 已经变了。创建 goroutine 到运行 goroutine 总会有时间差的,显然 for 循环一般比调度协程要快得多。

另一种写法
for i := 0; i < 10; i++ {
i := i
go func() {
fmt.Printf(“go i=%d\n”, i)
}()
}

c++可以指定捕获方式是传值还是引用,其他多数语言闭包捕获都是只传引用。

go 创建协程时,只求了方法入参的值,方法体里面的变量引用在代码执行到那里时才运算
for 循环中的 i 是多次迭代共享的,每次迭代会覆盖旧直值
所以当协程实际跑到访问 i 变量时,都不知道迭代到哪个地方了,值是不确定的

i 只初始化一次,作用域是 for 这个 block.
且 go routine 在大多数情况下遇到阻塞时都会放弃执行,所以 for loop 结束时,那些新起的 go routine 才开始被调度。
这种情况下可以通过加参数或者在 for loop block 中新建变量来解决,这叫捕获循环变量。
在使用 ide 的时候,go vet 会对这种情况有提示。

输出运行到 print 时候的值,一般因为循环的快,go 的慢,会出来全是 9

上面说的比较清楚了,go 关键字起的函数并不能保证立刻启动,大概率是 for 结束后才启动,这样造成打印时不能保证 i 的值是什么了。

解决办法有给函数加参数,另外也可以这么写。


for i := 0; i < 10; i++ {
i:=i
go func() {
fmt.Printf(“go i=%d\n”, i)
}()
}

i 是同一个变量,所有 goroutine 用到的都是同一个变量,所以你的程序是错的

需要在 go 语句前加一句 i := i,创建一个独立的变量。

在Golang(Go语言)中,使用for loop结合goroutine是一种常见的并发编程模式。这种模式可以让你并行处理多个任务,从而充分利用多核CPU的计算能力。然而,在使用时需要注意一些关键点,以避免常见的陷阱。

首先,要确保在for loop中正确地创建和管理goroutine。通常,你会在循环体内调用go关键字来启动一个新的goroutine。但要注意的是,这样做可能会导致大量的goroutine同时运行,从而耗尽系统资源。

为了避免这种情况,你可以使用诸如通道(channel)或限制goroutine数量的方法(如使用带缓冲的通道或信号量)来控制并发度。这样可以确保在任何时候,运行的goroutine数量都在一个可管理的范围内。

此外,还要注意goroutine的生命周期和数据的共享问题。由于goroutine是并发执行的,因此需要小心处理共享数据,以避免数据竞争和死锁等问题。可以使用Go提供的同步原语(如互斥锁、读写锁等)来保护共享数据。

最后,当使用for loopgoroutine时,还要确保所有goroutine都能正确结束,否则可能会导致程序无法正常退出或资源泄露。为此,可以使用诸如sync.WaitGroup等同步机制来等待所有goroutine完成。

总之,在使用for loop结合goroutine时,需要仔细考虑并发度、数据共享和goroutine的生命周期等问题,以确保程序的正确性和性能。

回到顶部