在下面的代码片段中,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")
Run Code Online (Sandbox Code Playgroud)
但是,这个for循环只从0到14运行.当我改变这个通道的长度(这取决于我有的任务元素的数量)时,for循环总是只运行一半len(tasks).为什么会这样?
背景:我使用缓冲通道执行任务,因为我打算在goroutine中执行每个任务,如果失败则处理任务.但是我现在已经将代码切换到for循环中的一个选择的情况,我很困惑为什么select case导致for循环只执行一半的时间.我确认这个for循环已经完成执行,并且在最后一次执行之后,i等于14(通道长度为30).
len(task) 如果你读的话会减少 tasks
使用空for来迭代地从任务中读取所有内容.
for {
select {
case task := <-tasks:
fmt.Println(task)
// Do something
}
if len(tasks) == 0 {break}
}
Run Code Online (Sandbox Code Playgroud)
或者您也可以使用范围:
for task := range tasks {
fmt.Println(task)
// Do something
if len(tasks) == 0 {break}
}
Run Code Online (Sandbox Code Playgroud)
break如果您不想锁定goroutine,请不要忘记此循环.
len(tasks)在每次迭代时重新评估.所以值是30,然后是29,然后是28,......最后,在中间len(tasks)交叉i,这就是它只打印一半值的原因.
那么,你可以做的是将长度存储在一个变量中:
n := len(tasks)
for i := 0; i < n; i++ { ... }
Run Code Online (Sandbox Code Playgroud)
或者,你可以简单地写
for len(tasks) > 0 { ... }
Run Code Online (Sandbox Code Playgroud)
如果要使用所有元素,range运算符的工作原理是:
for task := range tasks { ... }
Run Code Online (Sandbox Code Playgroud)
此外,请记住在使用完通道后关闭通道.