问题描述我有这样一个程序,他从一个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,我认为不是一个好的办法。因为,缓冲终归会满。
缥缈止盈
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的数量即可
- 2 回答
- 0 关注
- 471 浏览
添加回答
举报
0/150
提交
取消