我不理解的Go通道行为

huangapple go评论88阅读模式
英文:

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

我不理解的Go通道行为

英文:

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 &quot;fmt&quot;

func main() {

	mychnl := make(chan string, 2)

	go func(input chan string) {
		input &lt;- &quot;Inp1&quot;
		// If we remove this line the length of the chan in the print will be equal in both prints
		fmt.Println(&quot;Tell me why D:&quot;)
		input &lt;- &quot;Inp2&quot;
		input &lt;- &quot;Inp3&quot;
		input &lt;- &quot;Inp4&quot;
		close(input)
	}(mychnl)

	for res := range mychnl {
		fmt.Printf(&quot;Length of the channel is: %v The received value is: %s length need to be == &quot;, len(mychnl), res)
		fmt.Println(len(mychnl))
	}
}

/*
Output -&gt;
Line 13 = fmt.Println(&quot;Tell me why D:&quot;)

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
*/

我不理解的Go通道行为

答案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.

huangapple
  • 本文由 发表于 2022年5月23日 06:19:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/72341668.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定