如何在 Golang 中使用 goroutines 读取标准输入?
How to read from stdin with goroutines in Golang?
有问题列表。我将问题一个接一个地展示给用户,等待用户的回答。每个问题都应该在几秒钟内回答(例如 5 秒的问题)。如果问题得到正确及时的回答,则用户可以获得一些积分。
我的代码看起来像:
for i := 0; i < len(questions); i++ {
fmt.Println(questions[i].Text)
ans := make(chan int)
go func() {
fmt.Print("Enter answer ")
var u int
fmt.Scanf("%d\n", &u)
ans <- u
}()
select {
case userAnswer := <-ans:
if userAnswer == questions[i].Answer {
points++
}
case <-time.After(5 * time.Second):
fmt.Println("\n Time is over!")
}
}
下一个问题:如果用户不回答问题,那么他会按预期收到消息 "Time is over"。但是下一个答案不会被处理,用户应该重新输入。看起来像下一个输出:
question with answer 1
Enter answer: 1
1 is right answer
question with answer 2
Enter answer: 2
2 is right answer
question with answer 3
Enter answer:
Time is over!
question with answer 4
Enter answer: 4
4
4 is right answer
question with answer 5
Enter answer: 5
5 is right answer
用户没有回答问题#3,因此他需要回答问题#4 两次。
我知道这个问题是因为 goroutines 和 channels。但我不明白,为什么不是值,它是在超时后从标准输入读取的,发送到通道 "ans" 或从通道 "ans".
获取
为什么通道的值在超时后没有被正确接收?我如何重写代码,这样用户就不需要在上一个问题超时后重复输入两次?
抱歉英语不好,感谢您的帮助。
这里发生的事情是,当你超时时,你仍然有一个 fmt.Scanf
在前一个 goroutine 中进行。您还在每个循环中分配一个新频道。最终结果意味着问题 3 中的扫描得到您的第一个输入 4,然后尝试将其推送到一个永远不会被读取的通道上。第二次输入 4 时,新的 goroutine 会读取它,然后将其推送到您希望找到用户输入的频道。
相反,我建议您将用户输入卸载到单个 goroutine 中,该 goroutine 提供单个通道。
func readInput(input chan<- int) {
for {
var u int
_, err := fmt.Scanf("%d\n", &u)
if err != nil {
panic(err)
}
input <- u
}
}
然后像这样处理你的问题:
func main() {
var points int
userInput := make(chan int)
go readInput(userInput)
for i := 0; i < len(questions); i++ {
fmt.Println(questions[i].Text)
fmt.Print("Enter answer ")
select {
case userAnswer := <-userInput:
if userAnswer == questions[i].Answer {
fmt.Println("Correct answer:", userAnswer)
points++
} else {
fmt.Println("Wrong answer")
}
case <-time.After(5 * time.Second):
fmt.Println("\n Time is over!")
}
}
}
您可能想要添加一些额外的逻辑或处理以在某个时候终止输入读取 goroutine,这取决于您程序的实际生命周期,但这是一个不同的问题。
有问题列表。我将问题一个接一个地展示给用户,等待用户的回答。每个问题都应该在几秒钟内回答(例如 5 秒的问题)。如果问题得到正确及时的回答,则用户可以获得一些积分。 我的代码看起来像:
for i := 0; i < len(questions); i++ {
fmt.Println(questions[i].Text)
ans := make(chan int)
go func() {
fmt.Print("Enter answer ")
var u int
fmt.Scanf("%d\n", &u)
ans <- u
}()
select {
case userAnswer := <-ans:
if userAnswer == questions[i].Answer {
points++
}
case <-time.After(5 * time.Second):
fmt.Println("\n Time is over!")
}
}
下一个问题:如果用户不回答问题,那么他会按预期收到消息 "Time is over"。但是下一个答案不会被处理,用户应该重新输入。看起来像下一个输出:
question with answer 1
Enter answer: 1
1 is right answer
question with answer 2
Enter answer: 2
2 is right answer
question with answer 3
Enter answer:
Time is over!
question with answer 4
Enter answer: 4
4
4 is right answer
question with answer 5
Enter answer: 5
5 is right answer
用户没有回答问题#3,因此他需要回答问题#4 两次。 我知道这个问题是因为 goroutines 和 channels。但我不明白,为什么不是值,它是在超时后从标准输入读取的,发送到通道 "ans" 或从通道 "ans".
获取为什么通道的值在超时后没有被正确接收?我如何重写代码,这样用户就不需要在上一个问题超时后重复输入两次?
抱歉英语不好,感谢您的帮助。
这里发生的事情是,当你超时时,你仍然有一个 fmt.Scanf
在前一个 goroutine 中进行。您还在每个循环中分配一个新频道。最终结果意味着问题 3 中的扫描得到您的第一个输入 4,然后尝试将其推送到一个永远不会被读取的通道上。第二次输入 4 时,新的 goroutine 会读取它,然后将其推送到您希望找到用户输入的频道。
相反,我建议您将用户输入卸载到单个 goroutine 中,该 goroutine 提供单个通道。
func readInput(input chan<- int) {
for {
var u int
_, err := fmt.Scanf("%d\n", &u)
if err != nil {
panic(err)
}
input <- u
}
}
然后像这样处理你的问题:
func main() {
var points int
userInput := make(chan int)
go readInput(userInput)
for i := 0; i < len(questions); i++ {
fmt.Println(questions[i].Text)
fmt.Print("Enter answer ")
select {
case userAnswer := <-userInput:
if userAnswer == questions[i].Answer {
fmt.Println("Correct answer:", userAnswer)
points++
} else {
fmt.Println("Wrong answer")
}
case <-time.After(5 * time.Second):
fmt.Println("\n Time is over!")
}
}
}
您可能想要添加一些额外的逻辑或处理以在某个时候终止输入读取 goroutine,这取决于您程序的实际生命周期,但这是一个不同的问题。