douh9817 2018-06-10 23:06
浏览 39
已采纳

如何在Golang中使用goroutines从stdin读取?

There is list of questions. I show question one after one to user and wait for user`s answer. Every question should be answered in some seconds( for example 5 second for question). If question is answered right and in time, then user get some points. My code is looks like:

 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
", &u)
            ans <- u
        }()

        select {
        case userAnswer := <-ans:
            if userAnswer == questions[i].Answer {
                points++
            }
        case <-time.After(5 * time.Second):
            fmt.Println("
 Time is over!")
        }
    }

Problem is next: if user don`t answer to question, then he get message "Time is over", as expected. But next answer will not be processed, and user should type it again. It looks like next output:

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

User did not answer to question #3, so he need to answer to question #4 twice. I understand that problem is because goroutines and channels. But I don`t understand, why was not value, that was read from stdin after timeout, sent to or get from channel "ans".

Why value from channel was not properly received after timeout? How I can rewrite code, so user don`t need to repeat input twice after timeout to previous question?

Sorry for bad english and thanks for help.

  • 写回答

1条回答 默认 最新

  • doufang7385 2018-06-11 00:23
    关注

    What's going on here is that when you time out you still have a fmt.Scanf going in the previous goroutine. You're also allocating a new channel each loop. The end result means the scan from question 3 gets your first input of 4 and then tries to push it onto a channel that will never be read from. The second time you enter 4 it is read by the new goroutine and is then pushed onto the channel you're expecting to find the user's input on.

    I'd suggest, instead, that you offload the user input into a single goroutine that feeds a single channel.

    func readInput(input chan<- int) {
        for {
            var u int
            _, err := fmt.Scanf("%d
    ", &u)
            if err != nil {
                panic(err)
            }
            input <- u
        }
    }
    

    And then process your questions like so:

    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("
     Time is over!")
            }
        }
    }
    

    You would probably want to add some additional logic or handling to terminate the input reading goroutine at some point, depending on the actual life cycle of your program but that's a different problem.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥20 测距传感器数据手册i2c