在以下代码段中,tasks
是一个长度为30的缓冲通道,其中只包含30个元素。我正在写一个for
循环来操作每个任务,从一个通道读入。
for i := 0; i < len(tasks); i++ {
fmt.Println(i)
select {
case task := <-tasks:
fmt.Println(task)
// Do something
}
}
fmt.Println("Done")
但是,这个for循环只从0到14运行。当我改变这个通道的长度(取决于我拥有的任务元素的数量)时,for循环总是只运行len(tasks)
的一半。为什么会这样?
背景:
我使用缓冲通道执行任务,因为我打算在goroutine中执行每个任务,如果失败则处理任务。但是我现在已经将代码切换到for循环中的一个选择的情况,我很困惑为什么select case导致for循环只执行一半的时间。我确认这个for循环已经完成执行,并且在最后一次执行之后,i
等于14(通道长度为30)。
答案 0 :(得分:6)
len(task)
中读取,则 tasks
会减少
使用空for
迭代读取任务中的所有内容。
for {
select {
case task := <-tasks:
fmt.Println(task)
// Do something
}
if len(tasks) == 0 {break}
}
或者您也可以使用范围:
for task := range tasks {
fmt.Println(task)
// Do something
if len(tasks) == 0 {break}
}
如果您不想锁定goroutine,请不要忘记break
这个周期。
答案 1 :(得分:6)
len(tasks)
。所以值是30,然后是29,然后是28,......最后,len(tasks)
在中间穿过i
,这就是为什么它只打印了一半的值。
所以,你可以做的是将长度存储在一个变量中:
n := len(tasks)
for i := 0; i < n; i++ { ... }
或者,你可以简单地写
for len(tasks) > 0 { ... }
如果要使用所有元素,range
运算符将起作用:
for task := range tasks { ... }
另外,请务必在使用完毕后关闭频道。
答案 2 :(得分:0)
因为你从频道中取元素,它的长度减少了..
看看这个样本,我想你会很清楚:
https://play.golang.org/p/TC3HymIlhs