为了账号安全,请及时绑定邮箱和手机立即绑定

goroutine使用了外面的变量,造成闭包问题。怎么解决呢?

goroutine使用了外面的变量,造成闭包问题。怎么解决呢?

哆啦的时光机 2019-03-18 22:16:12
问题描述我有这样一个程序,他从一个items列表中读取items,然后,打印一下这个item,交个一个channel// 从out队列接收数据         for _,item := range result.Items {             fmt.Println("got item: ",item)            go func() {                 c.ItemChan <- item             }()         }在另一个地方,起了一个goroutine,来接收    go func() {         count := 0         for {             item := <- out             count++             fmt.Printf("获取到的item:%d,当前saver计数count是:%d\n",item,count)         }     }()很简单的一个东西,但是发现。写入是打印的item没有重复,但读取的channel,打印有重复。 最后发现应该是写入是,channel阻塞,而外层循环还在继续,导致item更新了,然后在写入channel的已经是几个相同的item了问题出现的环境背景及自己尝试过哪些方法我尝试给写入添加sleep,这样只要确保这个被消费了,然后在写入,就没问题        for _,item := range result.Items {             time.Sleep(time.Millisecond * 100)             fmt.Println("got item: ",item)            go func() {                 c.ItemChan <- item             }()         }但显然,这个不符合需求。那么,我的问题是,我有一个列表要不断读取,通过goroutine塞到一个channel里面,但这样会造成闭包问题,该怎么解决呢?也许,将写入改成一个大的goroutine是个好办法? goroutine包裹整个for循环,然后,此时在写入channel就是阻塞的了相关代码// 请把代码文本粘贴到下方(请勿用图片代替代码)你期待的结果是什么?实际看到的错误信息又是什么?
查看完整描述

2 回答

?
Cats萌萌

TA贡献1805条经验 获得超9个赞

自己思考了一下。其实,既然是闭包。那么,只要将item作为参数,传递给这个循环goroutine,就可以了 
他作为形参,自然不会被修改

// 从out队列接收数据
        for _,item := range result.Items {
            fmt.Println("got item: ",item)            go func(rec interface{}) {
                c.ItemChan <- rec
            }(item)
        }

带缓冲的channel,我认为不是一个好的办法。因为,缓冲终归会满。


查看完整回答
反对 回复 2019-03-18
?
缥缈止盈

TA贡献2041条经验 获得超4个赞

你打印写入的地方有问题。

for _,item := range result.Items {            //fmt.Println("got item: ",item)//把这个放 go func()里面
            go func() {
                fmt.Println("got item: ",item)
                c.ItemChan <- item
            }()
        }

这样你打印的就和接收到的数据是一样的了。
因为go func 并不能保证立即执行,在它还没有执行的时候,item值已经被for循环改变了

我有个疑问,你在写入的地方起goroutine是为了for循环不被写入阻塞吗?如果不想因为写入被阻塞,可以给channel定义一个缓冲。按照例子的,缓冲数定义为items的数量即可


查看完整回答
反对 回复 2019-03-18
  • 2 回答
  • 0 关注
  • 471 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信