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 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?