Go通道 – 向通道推送数据会停止执行。

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

Go Channels - Pushing to a channel stops execution

问题

我正在尝试创建一个命令行测验,用户会被问一个接一个的问题,直到他们回答完最后一个问题,或者超时。

我想使用通道来学习如何正确使用它们,但我遇到了一个问题。

我的想法是让 correctAnswersCh 从 0 开始,每回答一个正确的问题,它就加1。

测验总是在 quiz() 函数的第3行停止,即在将零放入通道后。

我在下面添加了一些代码,但完整的代码在这里:
https://play.golang.org/p/vzRCTc7MpIK

func main() {
	questions, err := getCsvData()
	var limit = time.Duration(3)

	
	flag.Parse()

	if err != nil {
		log.Fatal(err)
	}

	quizComplete := make(chan bool)
	correctAnswersCh := make(chan int)
	go quiz(quizComplete, questions, correctAnswersCh)

	select {
	case <-time.After(limit*time.Second):
		fmt.Println("超时")
	}
	fmt.Printf("正确答案: %v\n", <-correctAnswersCh)
}

func quiz(quizComplete chan bool, questions [][]string, correctAnswersCh chan int) {
	reader := bufio.NewReader(os.Stdin)
	correctAnswersCh <- 0
	// 执行在这里停止。将 0 添加到 correctAnswersCh,然后 quiz 函数停止
	for _, question := range questions {

		fmt.Print(question[0], "= ")
		answer, _ := reader.ReadString('\n')

		if strings.TrimSpace(answer) == question[1] {
			cA := <-correctAnswersCh
			cA++
			correctAnswersCh <- cA
		}
	}
	quizComplete <- true
}
英文:

I'm trying to create a command line quiz, where users would be asked question after question until they either finish the final question, or they are timed out.

I wanted to use channels so I could learn how to use them properly, and I've hit a blocker, so to speak.

The idea is for correctAnswersCh to start with 0, and after every correct answer, it will increment by 1.

The quiz always stops at line 3 of the quiz() function, after I put zero into the channel.

I've added some code below, but the full code is here:
https://play.golang.org/p/vzRCTc7MpIK

func main() {
	questions, err := getCsvData()
	var limit = time.Duration(3)

	
	flag.Parse()

	if err != nil {
		log.Fatal(err)
	}

	quizComplete := make(chan bool)
	correctAnswersCh := make(chan int)
	go quiz(quizComplete, questions, correctAnswersCh)

	select {
	case &lt;-time.After(limit*time.Second):
		fmt.Println(&quot;Timed Out&quot;)
	}
	fmt.Printf(&quot;Correct Answers: %v\n&quot;, &lt;-correctAnswersCh)
}

func quiz(quizComplete chan bool, questions [][]string, correctAnswersCh chan int) {
	reader := bufio.NewReader(os.Stdin)
	correctAnswersCh &lt;- 0
	// execution stops here.  0 is added to correctAnswersCh, then the quiz func stops
	for _, question := range questions {

		fmt.Print(question[0], &quot;= &quot;)
		answer, _ := reader.ReadString(&#39;\n&#39;)

		if strings.TrimSpace(answer) == question[1] {
			cA := &lt;-correctAnswersCh
			cA++
			correctAnswersCh &lt;- cA
		}
	}
	quizComplete &lt;- true
}

答案1

得分: 6

你的correctAnswersCh通道是无缓冲的,所以在有人接收之前,发送到该通道的任何内容都会被阻塞。而且由于你的main()函数只在超时后接收,所以你的应用程序会一直被阻塞。

一个简单的解决方法是给通道分配一个缓冲区:

correctAnswersCh := make(chan int, 1)

虽然这是一种奇怪的通道用法。如果你的意图是创建一个并发安全的计数器,可以使用原子计数器,例如atomic.AddInt32()。另一种选择是使用互斥锁(sync.Mutexsync.RWMutex)来保护在多个goroutine之间并发访问的资源(变量)。

英文:

Your correctAnswersCh channel is unbuffered, so sending anything on it blocks until there is someone receiving from it. And since your main() function only receives from it after the timeout, your app is blocked until then.

One simple workaround is to give 1 buffer to the channel:

correctAnswersCh := make(chan int, 1)

Although this is some weird usage of channels. If your intention is to create a concurrency safe counter, use an aotmic counter, e.g. atomic.AddInt32(). Another option is to use a mutex (sync.Mutex or sync.RWMutex) to protect a resource (variable) when accessed concurrently from multiple goroutines.

huangapple
  • 本文由 发表于 2019年11月18日 20:34:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/58914677.html
匿名

发表评论

匿名网友

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

确定