英文:
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 <-time.After(limit*time.Second):
fmt.Println("Timed Out")
}
fmt.Printf("Correct Answers: %v\n", <-correctAnswersCh)
}
func quiz(quizComplete chan bool, questions [][]string, correctAnswersCh chan int) {
reader := bufio.NewReader(os.Stdin)
correctAnswersCh <- 0
// execution stops here. 0 is added to correctAnswersCh, then the quiz func stops
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
}
答案1
得分: 6
你的correctAnswersCh
通道是无缓冲的,所以在有人接收之前,发送到该通道的任何内容都会被阻塞。而且由于你的main()
函数只在超时后接收,所以你的应用程序会一直被阻塞。
一个简单的解决方法是给通道分配一个缓冲区:
correctAnswersCh := make(chan int, 1)
虽然这是一种奇怪的通道用法。如果你的意图是创建一个并发安全的计数器,可以使用原子计数器,例如atomic.AddInt32()
。另一种选择是使用互斥锁(sync.Mutex
或sync.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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论