英文:
fmt.Println is not executing in order when used without sleep
问题
我正在尝试理解为什么我的代码表现不如我所期望。问题在于,我期望我的代码的行为如下:
- 定义通道
- 运行 goroutine 并开始循环
- 将值放入通道,打印 "finished"
- 开始第二次迭代,阻塞调用(通道中已经有值),转到主 goroutine
- 打印 1,尝试运行第二次迭代,主 goroutine 阻塞调用,返回到第二个 goroutine
- 循环重复
它的确按照这种方式工作,但只有在使用 time.Sleep 的情况下,但是出于某种原因,当注释掉 time.Sleep 时,它的行为完全不同。更有趣的是,有时对于像 Nanos 这样的非常小的时间值,此代码返回的结果甚至更加不同。有人能解释一下为什么会这样吗?我猜可能是 Println 在显示上太慢了,但这对我来说听起来很奇怪。。
谢谢
** 预期的结果:**
finished
1
finished
2
finished
3
finished
6
finished
4
finished
8
finished all
** 非预期的结果 **
finished
1
2
finished
finished
3
finished
6
4
finished
finished
8
finished all
func main() {
var c chan int = make(chan int)
go sendingThrowingResults(c)
for val := range c {
fmt.Println(val)
}
fmt.Println("finished all")
}
func sendingThrowingResults(c chan int) {
var results []int = []int{1, 2, 3, 6, 4, 8}
for _, val := range results {
//time.Sleep(100 * time.Millisecond)
c <- val
fmt.Println("finished")
}
defer close(c)
}
英文:
I'm trying to understand, why my code doesn't behave as I expect it. The problem is that I would expect, that my code would behave like that:
- Define channel
- Run goroutine and start looping
- Put value into channel, print "finished"
- Starting second iteration, blocking call(there is already value in the channel), move to main goroutine
- Printing 1, trying to run second iteration, blocking call for main goroutine, coming back to second goroutine
- Cycle repeats
It works like that, but only with time.Sleep, but for some reason when commenting out time.Sleep it behaves totally different. What's even more interesting that sometimes for really small values of time like Nanos etc this code returns even more different results. Could someone explain me, why it works like that? My guess is that maybe Println is too slow on display, but it sounds weird to me..
Thanks
** As expected: **
finished
1
finished
2
finished
3
finished
6
finished
4
finished
8
finished all
** Not expected **
finished
1
2
finished
finished
3
finished
6
4
finished
finished
8
finished all
func main() {
var c chan int = make(chan int)
go sendingThrowingResults(c)
for val := range c {
fmt.Println(val)
}
fmt.Println("finished all")
}
func sendingThrowingResults(c chan int) {
var results []int = []int{1, 2, 3, 6, 4, 8}
for _, val := range results {
//time.Sleep(100 * time.Millisecond)
c <- val
fmt.Println("finished")
}
defer close(c)
}
答案1
得分: 3
一个通道操作需要两边都参与。只有在读取器准备好时才会进行写入。一旦发生这种情况,就无法保证哪个goroutine会先运行。
因此,一旦通道写入发生,两个println语句中的一个将会按照某种随机顺序执行。
英文:
A channel operation needs both sides to participate. A write only happens when a reader is ready. Once that happens, there is no guarantee on which goroutine will run first.
Thus, once the channel write happens, one of the two printlns will work, in some random order.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论