英文:
Go Channels behaviour that i do not understand
问题
我最近开始学习Go语言,有一个情况让我不太理解,为什么在一行代码的改动下会导致两种不同的行为。
在第一次运行程序时,我运行了带有
的程序,然后在主程序中打印通道的长度,结果打印出0,而在紧接着的下一行打印出2(我指的是主程序打印的第一个值)。在第二次运行时,我删除了
,然后在两次打印中,第一次打印出通道的长度为2。在图片中,你可以看到控制台中的两个不同的打印结果,我不明白为什么它们会因为添加/删除第13行而不同。
// 我不理解的Go行为 /:
package main
import "fmt"
func main() {
mychnl := make(chan string, 2)
go func(input chan string) {
input <- "Inp1"
// 如果我们删除这一行,打印中的通道长度将在两次打印中相等
fmt.Println("Tell me why D:")
input <- "Inp2"
input <- "Inp3"
input <- "Inp4"
close(input)
}(mychnl)
for res := range mychnl {
fmt.Printf("通道的长度为:%v,接收到的值为:%s,长度应该为 == ", len(mychnl), res)
fmt.Println(len(mychnl))
}
}
输出结果:
第一次运行带有第13行的程序:
Tell me why D:
通道的长度为:0,接收到的值为:Inp1,长度应该为 == 2
通道的长度为:2,接收到的值为:Inp2,长度应该为 == 2
通道的长度为:1,接收到的值为:Inp3,长度应该为 == 1
通道的长度为:0,接收到的值为:Inp4,长度应该为 == 0
第二次运行删除了第13行的程序:
通道的长度为:2,接收到的值为:Inp1,长度应该为 == 2
通道的长度为:2,接收到的值为:Inp2,长度应该为 == 2
通道的长度为:1,接收到的值为:Inp3,长度应该为 == 1
通道的长度为:0,接收到的值为:Inp4,长度应该为 == 0
英文:
I recently started learning Go and there is a case that i have been written that i cannot understand why does he get two different behaviors based on a change made in a single line that just prints
,In the first run i run the program with
and then in the main routine when i print the length of the channel at that print 0 and in the next line thats just come after that its print 2 (I'm talking about the first print that the main routine made).In the second run i removed
and then in both prints in the first time that print thats the length of the channel is 2.in the picture you can see in the console the two diffrents prints that i dont understand why they are different [just because add/remove line 13].
// Go behavior that I do not understand /:
package main
import "fmt"
func main() {
mychnl := make(chan string, 2)
go func(input chan string) {
input <- "Inp1"
// If we remove this line the length of the chan in the print will be equal in both prints
fmt.Println("Tell me why D:")
input <- "Inp2"
input <- "Inp3"
input <- "Inp4"
close(input)
}(mychnl)
for res := range mychnl {
fmt.Printf("Length of the channel is: %v The received value is: %s length need to be == ", len(mychnl), res)
fmt.Println(len(mychnl))
}
}
/*
Output ->
Line 13 = fmt.Println("Tell me why D:")
First run with line 13:
Tell me why D:
Length of the channel is: 0 The received value is: Inp1 length need to be == 2
Length of the channel is: 2 The received value is: Inp2 length need to be == 2
Length of the channel is: 1 The received value is: Inp3 length need to be == 1
Length of the channel is: 0 The received value is: Inp4 length need to be == 0
Second run without line 13:
Length of the channel is: 2 The received value is: Inp1 length need to be == 2
Length of the channel is: 2 The received value is: Inp2 length need to be == 2
Length of the channel is: 1 The received value is: Inp3 length need to be == 1
Length of the channel is: 0 The received value is: Inp4 length need to be == 0
*/
答案1
得分: 1
你看到的行为是由于竞态条件引起的。通常情况下,你无法确定主 goroutine 打印通道长度的时间与其他 goroutine 写入通道的时间。通过添加打印语句,你会引发额外的 I/O(输出到 stdout),这通常意味着 goroutine 会让出执行权并重新调度。因此,你的 goroutine 写入通道的速度会受到 Print
语句的影响是不奇怪的。
在设计使用通道的程序时,请记住你不必过于关注通道上的并发操作发生的时间。当你从通道中读取时,通道上可能有一、两个或零个元素。因为通道是有缓冲的,并且两个 goroutine 可能会在现代计算机的多个核上并发运行,所以无法知道具体情况。对于缓冲通道的 len()
函数可能会返回各种可能的值,你不应该依赖它来保证算法的正确性。
英文:
The behavior you're seeing is due to a race condition. Generally, you can't be sure when the main goroutine will print the length of the channel compared to when the other goroutine will write to it.
By adding the print statement, you cause additional I/O (to stdout), which in turn often means that goroutines yield execution and are rescheduled. So it's not surprising that the Print
changes how fast your goroutine writes to the channel.
When designing programs with channels, keep in mind that you must not care too much when concurrent operations on the channel happen . Will one, two, or zerothings be on the channel when you read from it? There's no way to know, because the channel is buffered and the two goroutines are likely to run concurrently on the multiple cores of modern computers. len()
of a buffered channel is likely to lead to a variety of possible values, and you shouldn't rely on it for algorithmic correctness.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论